diff options
Diffstat (limited to 'test')
29 files changed, 2247 insertions, 59 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index b85594f7af..c924988d06 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -35,6 +35,20 @@ describe('buffer_* functions', function() eq('', curbuf('get_line', 0)) end) + it('get_line: out-of-bounds returns empty string', function() + curbuf('set_line', 0, 'line1.a') + eq('', curbuf('get_line', 1)) + eq('', curbuf('get_line', -2)) + end) + + it('set_line, del_line: out-of-bounds is an error', function() + curbuf('set_line', 0, 'line1.a') + eq(false, pcall(curbuf, 'set_line', 1, 'line1.b')) + eq(false, pcall(curbuf, 'set_line', -2, 'line1.b')) + eq(false, pcall(curbuf, 'del_line', 2)) + eq(false, pcall(curbuf, 'del_line', -3)) + end) + it('can handle NULs', function() curbuf('set_line', 0, 'ab\0cd') eq('ab\0cd', curbuf('get_line', 0)) @@ -43,6 +57,27 @@ describe('buffer_* functions', function() describe('{get,set}_line_slice', function() + it('get_line_slice: out-of-bounds returns empty array', function() + curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'}) + eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity + + eq({}, curbuf('get_line_slice', 2, 3, false, true)) + eq({}, curbuf('get_line_slice', 3, 9, true, true)) + eq({}, curbuf('get_line_slice', 3, -1, true, true)) + eq({}, curbuf('get_line_slice', -3, -4, false, true)) + eq({}, curbuf('get_line_slice', -4, -5, true, true)) + end) + + it('set_line_slice: out-of-bounds is an error', function() + curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'}) + eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity + + eq({'c'}, curbuf('get_line_slice', -1, 4, true, true)) + eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 5, true, true)) + eq(false, pcall(curbuf, 'set_line_slice', 4, 5, true, true, {'d'})) + eq(false, pcall(curbuf, 'set_line_slice', -4, -5, true, true, {'d'})) + end) + it('works', function() eq({''}, curbuf('get_line_slice', 0, -1, true, true)) -- Replace buffer diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c158c26341..9e880a4f04 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -34,6 +34,15 @@ describe('vim_* functions', function() end) end) + describe('call_function', function() + it('works', function() + nvim('call_function', 'setqflist', {{{ filename = 'something', lnum = 17}}, 'r'}) + eq(17, nvim('call_function', 'getqflist', {})[1].lnum) + eq(17, nvim('call_function', 'eval', {17})) + eq('foo', nvim('call_function', 'simplify', {'this/./is//redundant/../../../foo'})) + end) + end) + describe('strwidth', function() it('works', function() eq(3, nvim('strwidth', 'abc')) diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index 9282a66240..0550d22fa6 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -92,7 +92,7 @@ end) describe('clipboard usage', function() before_each(function() clear() - execute('let &rtp = "test/functional/clipboard,".&rtp') + execute('let &rtp = "test/functional/fixtures,".&rtp') execute('call getreg("*")') -- force load of provider end) @@ -197,6 +197,17 @@ describe('clipboard usage', function() expect('some more') end) + it('pastes unnamed register if the provider fails', function() + insert('the text') + feed('yy') + execute("let g:cliperror = 1") + feed('"*p') + expect([[ + the text + the text]]) + end) + + describe('with clipboard=unnamed', function() -- the basic behavior of unnamed register should be the same -- even when handled by clipboard provider @@ -221,12 +232,15 @@ describe('clipboard usage', function() expect('words') eq({{'words'}, 'v'}, eval("g:test_clip['*']")) + -- "+ shouldn't have changed + eq({''}, eval("g:test_clip['+']")) + execute("let g:test_clip['*'] = ['linewise stuff','']") feed('p') expect([[ words linewise stuff]]) - end) + end) it('does not clobber "0 when pasting', function() insert('a line') @@ -261,6 +275,60 @@ describe('clipboard usage', function() expect("indeed star") end) + it('unamed operations work even if the provider fails', function() + insert('the text') + feed('yy') + execute("let g:cliperror = 1") + feed('p') + expect([[ + the text + the text]]) + end) + + end) + + describe('with clipboard=unnamedplus', function() + before_each(function() + execute('set clipboard=unnamedplus') + end) + + it('links the "+ and unnamed registers', function() + insert("one two") + feed('^"+dwdw"+P') + expect('two') + eq({{'two'}, 'v'}, eval("g:test_clip['+']")) + + -- "* shouldn't have changed + eq({''}, eval("g:test_clip['*']")) + + execute("let g:test_clip['+'] = ['three']") + feed('p') + expect('twothree') + end) + + it('and unnamed, yanks to both', function() + execute('set clipboard=unnamedplus,unnamed') + insert([[ + really unnamed + text]]) + feed('ggdd"*p"+p') + expect([[ + text + really unnamed + really unnamed]]) + eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['+']")) + eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['*']")) + + -- unnamedplus takes predecence when pasting + execute("let g:test_clip['+'] = ['the plus','']") + execute("let g:test_clip['*'] = ['the star','']") + feed("p") + expect([[ + text + really unnamed + really unnamed + the plus]]) + end) end) it('supports :put', function() @@ -301,6 +369,7 @@ describe('clipboard usage', function() [2] = {foreground = Screen.colors.Blue}, [3] = {bold = true, foreground = Screen.colors.SeaGreen}}, {{bold = true, foreground = Screen.colors.Blue}}) + feed('<cr>') -- clear out of Press ENTER screen end) it('can paste "* to the commandline', function() @@ -335,4 +404,34 @@ describe('clipboard usage', function() 'Howdy!', }, 'v'}, eval("g:test_clip['*']")) end) + + it('handles middleclick correctly', function() + local screen = Screen.new(30, 5) + screen:attach() + insert([[ + the source + a target]]) + feed('gg"*ywwyw') + -- clicking depends on the exact visual layout, so expect it: + screen:expect([[ + the ^source | + a target | + ~ | + ~ | + | + ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + + feed('<MiddleMouse><0,1>') + expect([[ + the source + the a target]]) + + -- on error, fall back to unnamed register + execute("let g:cliperror = 1") + feed('<MiddleMouse><6,1>') + expect([[ + the source + the a sourcetarget]]) + end) + end) diff --git a/test/functional/eval/glob_spec.lua b/test/functional/eval/glob_spec.lua new file mode 100644 index 0000000000..136417249c --- /dev/null +++ b/test/functional/eval/glob_spec.lua @@ -0,0 +1,25 @@ +local helpers = require('test.functional.helpers') +local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq + +before_each(function() + clear() + lfs.mkdir('test-glob') + execute('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/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua new file mode 100644 index 0000000000..8ca2cca32c --- /dev/null +++ b/test/functional/eval/msgpack_functions_spec.lua @@ -0,0 +1,615 @@ +local helpers = require('test.functional.helpers') +local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute +local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq +local execute, source = helpers.execute, helpers.source +local nvim = helpers.nvim +describe('msgpack*() functions', function() + before_each(function() + clear() + end) + local obj_test = function(msg, obj) + it(msg, function() + nvim('set_var', 'obj', obj) + eq(obj, eval('msgpackparse(msgpackdump(g:obj))')) + 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('restore nil as special dict', function() + execute('let dumped = ["\\xC0"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL=0}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.nil')) + end) + + it('restore boolean false as zero', function() + execute('let dumped = ["\\xC2"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL=0}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.boolean')) + end) + + it('restore boolean true as one', function() + execute('let dumped = ["\\xC3"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL=1}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.boolean')) + end) + + it('dump string as BIN 8', function() + nvim('set_var', 'obj', {'Test'}) + eq({"\196\004Test"}, eval('msgpackdump(obj)')) + end) + + it('restore FIXSTR as special dict', function() + execute('let dumped = ["\\xa2ab"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL={'ab'}}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string')) + end) + + it('restore BIN 8 as string', function() + execute('let dumped = ["\\xC4\\x02ab"]') + eq({'ab'}, eval('msgpackparse(dumped)')) + end) + + it('restore FIXEXT1 as special dictionary', function() + execute('let dumped = ["\\xD4\\x10", ""]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext')) + end) + + it('restore MAP with BIN key as special dictionary', function() + execute('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL={{'a', ''}}}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) + end) + + it('restore MAP with duplicate STR keys as special dictionary', function() + execute('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]') + execute('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('restore MAP with MAP key as special dictionary', function() + execute('let dumped = ["\\x81\\x80\\xC4\\n"]') + execute('let parsed = msgpackparse(dumped)') + eq({{_TYPE={}, _VAL={{{}, ''}}}}, eval('parsed')) + eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) + end) + + it('can restore and dump UINT64_MAX', function() + execute('let dumped = ["\\xCF" . repeat("\\xFF", 8)]') + execute('let parsed = msgpackparse(dumped)') + execute('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 + eq(1, eval('0xFFFFFFFFFFFFFFFF == parsed[0]')) + 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() + execute('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]') + execute('let parsed = msgpackparse(dumped)') + execute('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 + eq(1, eval('-0x8000000000000000 == parsed[0]')) + 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() + execute('let dumped = ["\\xC4\\x01\\n"]') + execute('let parsed = msgpackparse(dumped)') + execute('let dumped2 = msgpackdump(parsed)') + eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed')) + eq(1, eval('parsed[0]._TYPE is v:msgpack_types.binary')) + eq(1, eval('dumped ==# dumped2')) + end) + + it('can restore and dump STR string with zero byte', function() + execute('let dumped = ["\\xA1\\n"]') + execute('let parsed = msgpackparse(dumped)') + execute('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() + execute('let dumped = ["\\xC4\\x01", ""]') + execute('let parsed = msgpackparse(dumped)') + execute('let dumped2 = msgpackdump(parsed)') + eq({"\n"}, eval('parsed')) + eq(1, eval('dumped ==# dumped2')) + end) + + it('can dump generic mapping with generic mapping keys and values', function() + execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') + execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') + execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') + execute('call add(todump._VAL, [todumpv1, todumpv2])') + eq({'\129\128\128'}, eval('msgpackdump([todump])')) + end) + + it('can dump generic mapping with ext', function() + execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') + eq({'\212\005', ''}, eval('msgpackdump([todump])')) + end) + + it('can dump generic mapping with array', function() + execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') + eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])')) + end) + + it('can dump generic mapping with UINT64_MAX', function() + execute('let todump = {"_TYPE": v:msgpack_types.integer}') + execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') + eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])')) + end) + + it('can dump generic mapping with INT64_MIN', function() + execute('let todump = {"_TYPE": v:msgpack_types.integer}') + execute('let todump._VAL = [-1, 2, 0, 0]') + eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])')) + end) + + it('dump and restore generic mapping with floating-point value', function() + execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}') + eq({0.125}, eval('msgpackparse(msgpackdump([todump]))')) + end) + + it('fails to dump a function reference', function() + execute('let Todump = function("tr")') + execute([[ + try + let dumped = msgpackdump([Todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: attempt to dump function reference', + eval('exception')) + end) + + it('fails to dump a function reference in a list', function() + execute('let todump = [function("tr")]') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: attempt to dump function reference', + eval('exception')) + end) + + it('fails to dump a recursive list', function() + execute('let todump = [[[]]]') + execute('call add(todump[0][0], todump)') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('fails to dump a recursive dict', function() + execute('let todump = {"d": {"d": {}}}') + execute('call extend(todump.d.d, {"d": todump})') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('fails to dump a recursive list in a special dict', function() + execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') + execute('call add(todump._VAL, todump)') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('fails to dump a recursive (key) map in a special dict', function() + execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') + execute('call add(todump._VAL, [todump, 0])') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('fails to dump a recursive (val) map in a special dict', function() + execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') + execute('call add(todump._VAL, [0, todump])') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('fails to dump a recursive (val) special list in a special dict', + function() + execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') + execute('call add(todump._VAL, [0, todump._VAL])') + execute([[ + try + let dumped = msgpackdump([todump]) + let exception = 0 + catch + let exception = v:exception + endtry + ]]) + eq('Vim(let):E475: Invalid argument: container references itself', + eval('exception')) + end) + + it('msgpackparse(systemlist(...)) does not segfault. #3135', function() + local cmd = "msgpackparse(systemlist('" + ..helpers.nvim_prog.." --api-info'))['_TYPE']['_VAL'][0][0]" + local api_info = eval(cmd) + api_info = eval(cmd) -- do it again (try to force segfault) + api_info = eval(cmd) -- do it again + eq('functions', api_info) + end) +end) diff --git a/test/functional/ex_cmds/grep_spec.lua b/test/functional/ex_cmds/grep_spec.lua new file mode 100644 index 0000000000..9c792099c1 --- /dev/null +++ b/test/functional/ex_cmds/grep_spec.lua @@ -0,0 +1,22 @@ +local helpers = require('test.functional.helpers') +local clear, execute, nvim, feed, eq, ok, eval = + helpers.clear, helpers.execute, helpers.nvim, helpers.feed, + helpers.eq, helpers.ok, helpers.eval + +describe(':grep', function() + before_each(clear) + + it('does not hang on large input #2983', function() + if eval("executable('grep')") == 0 then + pending('missing "grep" command') + return + end + + execute([[set grepprg=grep\ -r]]) + -- Change to test directory so that the test does not run too long. + execute('cd test') + execute('grep a **/*') + feed('<cr>') -- Press ENTER + ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1 + end) +end) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua new file mode 100644 index 0000000000..6af889bf9e --- /dev/null +++ b/test/functional/ex_cmds/menu_spec.lua @@ -0,0 +1,38 @@ +local helpers = require('test.functional.helpers') +local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim +local expect = helpers.expect +local feed = helpers.feed +local command = helpers.command + +describe(':emenu', function() + + before_each(function() + clear() + execute('nnoremenu Test.Test inormal<ESC>') + execute('inoremenu Test.Test insert') + execute('vnoremenu Test.Test x') + end) + + it('executes correct bindings in normal mode without using API', function() + execute('emenu Test.Test') + expect('normal') + end) + + it('executes correct bindings in normal mode', function() + command('emenu Test.Test') + expect('normal') + end) + + it('executes correct bindings in insert mode', function() + feed('i') + command('emenu Test.Test') + expect('insert') + end) + + it('executes correct bindings in visual mode', function() + feed('iabcde<ESC>0lvll') + command('emenu Test.Test') + expect('ae') + end) + +end) diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua index d4c9477133..b92739e40e 100644 --- a/test/functional/ex_cmds/recover_spec.lua +++ b/test/functional/ex_cmds/recover_spec.lua @@ -20,11 +20,11 @@ describe(':preserve', function() local swapdir = lfs.currentdir()..'/testdir_recover_spec' before_each(function() clear() - os.remove(swapdir) + helpers.rmdir(swapdir) lfs.mkdir(swapdir) end) after_each(function() - os.remove(swapdir) + helpers.rmdir(swapdir) end) it("saves to custom 'directory' and (R)ecovers (issue #1836)", function() diff --git a/test/functional/clipboard/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim index d88b68464e..0935ea45ff 100644 --- a/test/functional/clipboard/autoload/provider/clipboard.vim +++ b/test/functional/fixtures/autoload/provider/clipboard.vim @@ -3,18 +3,28 @@ let g:test_clip = { '+': [''], '*': [''], } let s:methods = {} let g:cliplossy = 0 +let g:cliperror = 0 function! s:methods.get(reg) + if g:cliperror + return 0 + end + let reg = a:reg == '"' ? '+' : a:reg if g:cliplossy " behave like pure text clipboard - return g:test_clip[a:reg][0] + return g:test_clip[reg][0] else - "behave like VIMENC clipboard - return g:test_clip[a:reg] + " behave like VIMENC clipboard + return g:test_clip[reg] end endfunction function! s:methods.set(lines, regtype, reg) + if a:reg == '"' + call s:methods.set(a:lines,a:regtype,'+') + call s:methods.set(a:lines,a:regtype,'*') + return 0 + end let g:test_clip[a:reg] = [a:lines, a:regtype] endfunction diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 33d04616a0..1159707282 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -6,7 +6,6 @@ local AsyncSession = require('nvim.async_session') local Session = require('nvim.session') local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim' ---- FIXME: 'autoindent' messes up the insert() function local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--cmd', 'set shortmess+=I background=light noswapfile noautoindent', '--embed'} @@ -290,6 +289,28 @@ local function expect(contents) return eq(dedent(contents), curbuf_contents()) end +local function rmdir(path) + if lfs.attributes(path, 'mode') ~= 'directory' then + return nil + end + for file in lfs.dir(path) do + if file == '.' or file == '..' then + goto continue + end + ret, err = os.remove(path..'/'..file) + if not ret then + error('os.remove: '..err) + return nil + end + ::continue:: + end + ret, err = os.remove(path) + if not ret then + error('os.remove: '..err) + end + return ret +end + return { clear = clear, spawn = spawn, @@ -321,5 +342,6 @@ return { curbuf_contents = curbuf_contents, wait = wait, set_session = set_session, - write_file = write_file + write_file = write_file, + rmdir = rmdir } diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua index b60f9ff7a4..7085d61cc7 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/job/job_spec.lua @@ -304,7 +304,7 @@ describe('jobs', function() source([[ call rpcnotify(g:channel, 'wait', jobwait([ \ jobstart([&sh, '-c', 'exit 4']), - \ jobstart([&sh, '-c', 'sleep 10000; exit 5']), + \ jobstart([&sh, '-c', 'sleep 10; exit 5']), \ ], 100)) ]]) eq({'notification', 'wait', {{4, -1}}}, next_msg()) diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua new file mode 100644 index 0000000000..585b391198 --- /dev/null +++ b/test/functional/legacy/057_sort_spec.lua @@ -0,0 +1,603 @@ +-- Tests for :sort command. + +local helpers = require('test.functional.helpers') +local insert, execute, clear, expect, eq, eval, source = helpers.insert, + helpers.execute, helpers.clear, helpers.expect, helpers.eq, helpers.eval, + helpers.source + +describe(':sort', function() + local text = [[ + abc + ab + a + a321 + a123 + a122 + b321 + b123 + c123d + 123b + c321d + b322b + b321 + b321b + ]] + before_each(clear) + + it('alphabetical', function() + insert(text) + execute('sort') + expect([[ + + 123b + a + a122 + a123 + a321 + ab + abc + b123 + b321 + b321 + b321b + b322b + c123d + c321d]]) + end) + + it('numerical', function() + insert([[ + abc + ab + a321 + a123 + a122 + a + x-22 + b321 + b123 + c123d + -24 + 123b + c321d + 0 + b322b + b321 + b321b + ]]) + execute('sort n') + expect([[ + abc + ab + a + + -24 + x-22 + 0 + a122 + a123 + b123 + c123d + 123b + a321 + b321 + c321d + b321 + b321b + b322b]]) + end) + + it('hexadecimal', function() + insert(text) + execute('sort x') + expect([[ + + a + ab + abc + 123b + a122 + a123 + a321 + b123 + b321 + b321 + b321b + b322b + c123d + c321d]]) + end) + + it('alphabetical, unique', function() + insert(text) + execute('sort u') + expect([[ + + 123b + a + a122 + a123 + a321 + ab + abc + b123 + b321 + b321b + b322b + c123d + c321d]]) + end) + + it('alphabetical, reverse', function() + insert(text) + execute('sort!') + expect([[ + c321d + c123d + b322b + b321b + b321 + b321 + b123 + abc + ab + a321 + a123 + a122 + a + 123b + ]]) + end) + + it('numerical, reverse', function() + insert(text) + execute('sort! n') + expect([[ + b322b + b321b + b321 + c321d + b321 + a321 + 123b + c123d + b123 + a123 + a122 + + a + ab + abc]]) + end) + + it('unique, reverse', function() + insert(text) + execute('sort! u') + expect([[ + c321d + c123d + b322b + b321b + b321 + b123 + abc + ab + a321 + a123 + a122 + a + 123b + ]]) + end) + + it('octal', function() + insert(text) + execute('sort o') + expect([[ + abc + ab + a + + a122 + a123 + b123 + c123d + 123b + a321 + b321 + c321d + b321 + b321b + b322b]]) + end) + + it('reverse, hexadecimal', function() + insert(text) + execute('sort! x') + expect([[ + c321d + c123d + b322b + b321b + b321 + b321 + b123 + a321 + a123 + a122 + 123b + abc + ab + a + ]]) + end) + + it('alphabetical, skip first character', function() + insert(text) + execute('sort/./') + expect([[ + a + + a122 + a123 + b123 + 123b + c123d + a321 + b321 + b321 + b321b + c321d + b322b + ab + abc]]) + end) + + it('alphabetical, skip first 2 characters', function() + insert(text) + execute('sort/../') + expect([[ + ab + a + + a321 + b321 + b321 + b321b + c321d + a122 + b322b + a123 + b123 + 123b + c123d + abc]]) + end) + + it('alphabetical, unique, skip first 2 characters', function() + insert(text) + execute('sort/../u') + expect([[ + ab + a + + a321 + b321 + b321b + c321d + a122 + b322b + a123 + b123 + 123b + c123d + abc]]) + end) + + it('numerical, skip first character', function() + insert(text) + execute('sort/./n') + expect([[ + abc + ab + a + + a122 + a123 + b123 + c123d + 123b + a321 + b321 + c321d + b321 + b321b + b322b]]) + end) + + it('alphabetical, sort on first character', function() + insert(text) + execute('sort/./r') + expect([[ + + 123b + abc + ab + a + a321 + a123 + a122 + b321 + b123 + b322b + b321 + b321b + c123d + c321d]]) + end) + + it('alphabetical, sort on first 2 characters', function() + insert(text) + execute('sort/../r') + expect([[ + a + + 123b + a123 + a122 + a321 + abc + ab + b123 + b321 + b322b + b321 + b321b + c123d + c321d]]) + end) + + it('numerical, sort on first character', function() + insert(text) + execute('sort/./rn') + expect([[ + abc + ab + a + a321 + a123 + a122 + b321 + b123 + c123d + 123b + c321d + b322b + b321 + b321b + ]]) + end) + + it('alphabetical, skip past first digit', function() + insert(text) + execute([[sort/\d/]]) + expect([[ + abc + ab + a + + a321 + b321 + b321 + b321b + c321d + a122 + b322b + a123 + b123 + 123b + c123d]]) + end) + + it('alphabetical, sort on first digit', function() + insert(text) + execute([[sort/\d/r]]) + expect([[ + abc + ab + a + + a123 + a122 + b123 + c123d + 123b + a321 + b321 + c321d + b322b + b321 + b321b]]) + end) + + it('numerical, skip past first digit', function() + insert(text) + execute([[sort/\d/n]]) + expect([[ + abc + ab + a + + a321 + b321 + c321d + b321 + b321b + a122 + b322b + a123 + b123 + c123d + 123b]]) + end) + + it('numerical, sort on first digit', function() + insert(text) + execute([[sort/\d/rn]]) + expect([[ + abc + ab + a + + a123 + a122 + b123 + c123d + 123b + a321 + b321 + c321d + b322b + b321 + b321b]]) + end) + + it('alphabetical, skip past first 2 digits', function() + insert(text) + execute([[sort/\d\d/]]) + expect([[ + abc + ab + a + + a321 + b321 + b321 + b321b + c321d + a122 + b322b + a123 + b123 + 123b + c123d]]) + end) + + it('numerical, skip past first 2 digits', function() + insert(text) + execute([[sort/\d\d/n]]) + expect([[ + abc + ab + a + + a321 + b321 + c321d + b321 + b321b + a122 + b322b + a123 + b123 + c123d + 123b]]) + end) + + it('hexadecimal, skip past first 2 digits', function() + insert(text) + execute([[sort/\d\d/x]]) + expect([[ + abc + ab + a + + a321 + b321 + b321 + a122 + a123 + b123 + b321b + c321d + b322b + 123b + c123d]]) + end) + + it('alpha, on first 2 digits', function() + insert(text) + execute([[sort/\d\d/r]]) + expect([[ + abc + ab + a + + a123 + a122 + b123 + c123d + 123b + a321 + b321 + c321d + b322b + b321 + b321b]]) + end) + + it('numeric, on first 2 digits', function() + insert(text) + execute([[sort/\d\d/rn]]) + expect([[ + abc + ab + a + + a123 + a122 + b123 + c123d + 123b + a321 + b321 + c321d + b322b + b321 + b321b]]) + end) + + it('hexadecimal, on first 2 digits', function() + insert(text) + execute([[sort/\d\d/rx]]) + expect([[ + abc + ab + a + + a123 + a122 + b123 + c123d + 123b + a321 + b321 + c321d + b322b + b321 + b321b]]) + end) + + it('fails with wrong arguments', function() + insert(text) + -- This should fail with "E474: Invalid argument". + source([[ + try + sort no + catch + let tmpvar = v:exception + endtry]]) + eq('Vim(sort):E474: Invalid argument', eval('tmpvar')) + expect(text) + end) +end) diff --git a/test/functional/legacy/060_exists_and_has_functions_spec.lua b/test/functional/legacy/060_exists_and_has_functions_spec.lua index c4d2b01522..e9b79b490d 100644 --- a/test/functional/legacy/060_exists_and_has_functions_spec.lua +++ b/test/functional/legacy/060_exists_and_has_functions_spec.lua @@ -1,18 +1,15 @@ --- Tests for the exists() and has() functions. ts=8 sw=2 +-- Tests for the exists() and has() functions. local helpers = require('test.functional.helpers') local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect local write_file = helpers.write_file -local os = require('os') describe('exists() and has() functions', function() - setup(clear) - - it('is working', function() - + setup(function() + clear() -- Create a temporary script needed for the test. - write_file('test60.vim', [=[ + write_file('test60.vim', [[ " Vim script for exists() function test " Script-local variables are checked here @@ -110,7 +107,14 @@ describe('exists() and has() functions', function() echo "FAILED" endif unlet str - ]=]) + ]]) + end) + teardown(function() + os.remove('test.out') + os.remove('test60.vim') + end) + + it('is working', function() source([=[ " Add the special directory with test scripts to &rtp @@ -648,7 +652,7 @@ describe('exists() and has() functions', function() ]=]) -- Assert buffer contents. - expect([=[ + expect([[ #myagroup: 1 OK @@ -859,11 +863,7 @@ describe('exists() and has() functions', function() has patch 7.1.999: 1 has patch 7.4.123: 1 has patch 9.1.0: 0 - has patch 9.9.1: 0]=]) + has patch 9.9.1: 0]]) end) - teardown(function() - os.remove('test.out') - os.remove('test60.vim') - end) end) diff --git a/test/functional/legacy/062_tab_pages_spec.lua b/test/functional/legacy/062_tab_pages_spec.lua new file mode 100644 index 0000000000..6bbb06f9a7 --- /dev/null +++ b/test/functional/legacy/062_tab_pages_spec.lua @@ -0,0 +1,240 @@ +-- Tests for tab pages + +local helpers = require('test.functional.helpers') +local feed, insert, source, clear, execute, expect, eval, eq = + helpers.feed, helpers.insert, helpers.source, helpers.clear, + helpers.execute, helpers.expect, helpers.eval, helpers.eq + +describe('tab pages', function() + before_each(clear) + + it('can be opened and closed', function() + execute('tabnew') + eq(2, eval('tabpagenr()')) + execute('quit') + eq(1, eval('tabpagenr()')) + end) + + it('can be iterated with :tabdo', function() + source([[ + 0tabnew + 1tabnew + $tabnew + tabdo call append(line('$'), 'this is tab page ' . tabpagenr()) + tabclose! 2 + tabrewind + ]]) + eq('this is tab page 1', eval("getline('$')")) + execute('tablast') + eq('this is tab page 4', eval("getline('$')")) + end) + + it('have local variables accasible with settabvar()/gettabvar()', function() + -- Test for settabvar() and gettabvar() functions. Open a new tab page and + -- set 3 variables to a number, string and a list. Verify that the + -- variables are correctly set. + source([[ + tabnew + tabfirst + call settabvar(2, 'val_num', 100) + call settabvar(2, 'val_str', 'SetTabVar test') + call settabvar(2, 'val_list', ['red', 'blue', 'green']) + ]]) + + eq(100, eval('gettabvar(2, "val_num")')) + eq('SetTabVar test', eval('gettabvar(2, "val_str")')) + eq({'red', 'blue', 'green'}, eval('gettabvar(2, "val_list")')) + execute('tabnext 2') + eq(100, eval('t:val_num')) + eq('SetTabVar test', eval('t:val_str')) + eq({'red', 'blue', 'green'}, eval('t:val_list')) + end) + + it('work together with the drop feature and loaded buffers', function() + -- Test for ":tab drop exist-file" to keep current window. + execute('sp test1') + execute('tab drop test1') + eq(1, eval('tabpagenr("$")')) + eq(2, eval('winnr("$")')) + eq(1, eval('winnr()')) + end) + + it('work together with the drop feature and new files', function() + -- Test for ":tab drop new-file" to keep current window of tabpage 1. + execute('split') + execute('tab drop newfile') + eq(2, eval('tabpagenr("$")')) + eq(2, eval('tabpagewinnr(1, "$")')) + eq(1, eval('tabpagewinnr(1)')) + end) + + it('work together with the drop feature and multi loaded buffers', function() + -- Test for ":tab drop multi-opend-file" to keep current tabpage and + -- window. + execute('new test1') + execute('tabnew') + execute('new test1') + execute('tab drop test1') + eq(2, eval('tabpagenr()')) + eq(2, eval('tabpagewinnr(2, "$")')) + eq(1, eval('tabpagewinnr(2)')) + end) + + it('can be navigated with :tabmove', function() + execute('lang C') + execute('for i in range(9) | tabnew | endfor') + feed('1gt') + eq(1, eval('tabpagenr()')) + execute('tabmove 5') + eq(6, eval('tabpagenr()')) + execute('tabmove -2') + eq(4, eval('tabpagenr()')) + execute('tabmove +4') + eq(8, eval('tabpagenr()')) + execute('tabmove') + eq(10, eval('tabpagenr()')) + execute('tabmove -20') + eq(1, eval('tabpagenr()')) + execute('tabmove +20') + eq(10, eval('tabpagenr()')) + execute('3tabmove') + eq(4, eval('tabpagenr()')) + execute('7tabmove 5') + eq(6, eval('tabpagenr()')) + execute('let a="No error caught."') + execute('try') + execute('tabmove foo') + execute('catch E474') + execute('let a="E474 caught."') + execute('endtry') + eq('E474 caught.', eval('a')) + end) + + it('can trigger certain autocommands', function() + insert('Results:') + + -- Test autocommands. + source([[ + tabonly! + let g:r=[] + command -nargs=1 -bar C :call add(g:r, '=== '.<q-args>.' ===')|<args> + function Test() + autocmd TabEnter * :call add(g:r, 'TabEnter') + autocmd WinEnter * :call add(g:r, 'WinEnter') + autocmd BufEnter * :call add(g:r, 'BufEnter') + autocmd TabLeave * :call add(g:r, 'TabLeave') + autocmd WinLeave * :call add(g:r, 'WinLeave') + autocmd BufLeave * :call add(g:r, 'BufLeave') + let t:a='a' + C tab split + let t:a='b' + C tabnew + let t:a='c' + call add(g:r, join(map(range(1, tabpagenr('$')), + \ 'gettabvar(v:val, "a")'))) + C call map(range(1, tabpagenr('$')), + \ 'settabvar(v:val, ''a'', v:val*2)') + call add(g:r, join(map(range(1, tabpagenr('$')), + \ 'gettabvar(v:val, "a")'))) + let w:a='a' + C vsplit + let w:a='a' + let tabn=tabpagenr() + let winr=range(1, winnr('$')) + C tabnext 1 + call add(g:r, join(map(copy(winr), + \ 'gettabwinvar('.tabn.', v:val, "a")'))) + C call map(copy(winr), + \ 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)') + call add(g:r, join(map(copy(winr), + \ 'gettabwinvar('.tabn.', v:val, "a")'))) + augroup TabDestructive + autocmd TabEnter * :C tabnext 2 | C tabclose 3 + augroup END + C tabnext 3 + let g:r+=[tabpagenr().'/'.tabpagenr('$')] + autocmd! TabDestructive TabEnter + C tabnew + C tabnext 1 + autocmd TabDestructive TabEnter * nested + \ :C tabnext 2 | C tabclose 3 + C tabnext 3 + let g:r+=[tabpagenr().'/'.tabpagenr('$')] + endfunction + call Test() + $ put =g:r + ]]) + + -- Assert buffer contents. + expect([[ + Results: + === tab split === + WinLeave + TabLeave + WinEnter + TabEnter + === tabnew === + WinLeave + TabLeave + WinEnter + TabEnter + BufLeave + BufEnter + a b c + === call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)') === + 2 4 6 + === vsplit === + WinLeave + WinEnter + === tabnext 1 === + BufLeave + WinLeave + TabLeave + WinEnter + TabEnter + BufEnter + a a + === call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)') === + 2 4 + === tabnext 3 === + BufLeave + WinLeave + TabLeave + WinEnter + TabEnter + === tabnext 2 === + === tabclose 3 === + 2/2 + === tabnew === + WinLeave + TabLeave + WinEnter + TabEnter + BufLeave + BufEnter + === tabnext 1 === + BufLeave + WinLeave + TabLeave + WinEnter + TabEnter + BufEnter + === tabnext 3 === + BufLeave + WinLeave + TabLeave + WinEnter + TabEnter + === tabnext 2 === + BufLeave + WinLeave + TabLeave + WinEnter + TabEnter + === tabnext 2 === + === tabclose 3 === + BufEnter + === tabclose 3 === + 2/2]]) + end) +end) diff --git a/test/functional/legacy/077_mf_hash_grow_spec.lua b/test/functional/legacy/077_mf_hash_grow_spec.lua index 01d916ef04..825f08e968 100644 --- a/test/functional/legacy/077_mf_hash_grow_spec.lua +++ b/test/functional/legacy/077_mf_hash_grow_spec.lua @@ -15,7 +15,7 @@ describe('mf_hash_grow()', function() -- Check to see if cksum exists, otherwise skip the test if os.execute('which cksum 2>&1 > /dev/null') ~= 0 then - pending("was not tested because cksum was not found") + pending('was not tested because cksum was not found', function() end) else it('is working', function() execute('set fileformat=unix undolevels=-1') diff --git a/test/functional/legacy/080_substitute_spec.lua b/test/functional/legacy/080_substitute_spec.lua new file mode 100644 index 0000000000..89ef7a713c --- /dev/null +++ b/test/functional/legacy/080_substitute_spec.lua @@ -0,0 +1,162 @@ +-- Test for *sub-replace-special* and *sub-replace-expression* on substitue(). +-- Test for submatch() on substitue(). +-- Test for *:s%* on :substitute. + +local helpers = require('test.functional.helpers') +local feed, insert, source = helpers.feed, helpers.insert, helpers.source +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect +local eq, eval = helpers.eq, helpers.eval + +describe('substitue()', function() + before_each(clear) + + -- The original test contained several TEST_X lines to delimit different + -- parts. These where used to split the test into different it() blocks. + -- The TEST_X strings are repeated in the description of the blocks to make + -- it easier to incorporate upstream changes. + + local function test_1_and_2() + eq('AA', eval("substitute('A', 'A', '&&', '')")) + eq('&', eval([[substitute('B', 'B', '\&', '')]])) + eq('C123456789987654321', eval([[substitute('C123456789', ]] .. + [['C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] .. + [['\0\9\8\7\6\5\4\3\2\1', '')]])) + eq('d', eval("substitute('D', 'D', 'd', '')")) + eq('~', eval("substitute('E', 'E', '~', '')")) + eq('~', eval([[substitute('F', 'F', '\~', '')]])) + eq('Gg', eval([[substitute('G', 'G', '\ugg', '')]])) + eq('Hh', eval([[substitute('H', 'H', '\Uh\Eh', '')]])) + eq('iI', eval([[substitute('I', 'I', '\lII', '')]])) + eq('jJ', eval([[substitute('J', 'J', '\LJ\EJ', '')]])) + eq('Kk', eval([[substitute('K', 'K', '\Uk\ek', '')]])) + eq('l\rl', eval("substitute('lLl', 'L', '\r', '')")) + eq('m\rm', eval([[substitute('mMm', 'M', '\r', '')]])) + eq('n\rn', eval("substitute('nNn', 'N', '\\\r', '')")) + eq('o\no', eval([[substitute('oOo', 'O', '\n', '')]])) + eq('p\bp', eval([[substitute('pPp', 'P', '\b', '')]])) + eq('q\tq', eval([[substitute('qQq', 'Q', '\t', '')]])) + eq('r\\r', eval([[substitute('rRr', 'R', '\\', '')]])) + eq('scs', eval([[substitute('sSs', 'S', '\c', '')]])) + eq('t\rt', eval([[substitute('tTt', 'T', "\r", '')]])) + eq('u\nu', eval([[substitute('uUu', 'U', "\n", '')]])) + eq('v\bv', eval([[substitute('vVv', 'V', "\b", '')]])) + eq('w\\w', eval([[substitute('wWw', 'W', "\\", '')]])) + eq('XxxX', eval([[substitute('X', 'X', '\L\uxXx\l\EX', '')]])) + eq('yYYy', eval([[substitute('Y', 'Y', '\U\lYyY\u\Ey', '')]])) + end + + it('with "set magic" (TEST_1)', function() + execute('set magic') + test_1_and_2() + end) + + it('with "set nomagic" (TEST_2)', function() + execute('set nomagic') + test_1_and_2() + end) + + it('with sub-replace-expression (TEST_3)', function() + execute('set magic&') + eq('a\\a', eval([[substitute('aAa', 'A', '\="\\"', '')]])) + eq('b\\\\b', eval([[substitute('bBb', 'B', '\="\\\\"', '')]])) + eq('c\rc', eval([[substitute('cCc', 'C', '\="]]..'\r'..[["', '')]])) + eq('d\\\rd', eval([[substitute('dDd', 'D', '\="\\]]..'\r'..[["', '')]])) + eq('e\\\\\re', + eval([[substitute('eEe', 'E', '\="\\\\]]..'\r'..[["', '')]])) + eq('f\\rf', eval([[substitute('fFf', 'F', '\="\\r"', '')]])) + eq('j\\nj', eval([[substitute('jJj', 'J', '\="\\n"', '')]])) + eq('k\rk', eval([[substitute('kKk', 'K', '\="\r"', '')]])) + eq('l\nl', eval([[substitute('lLl', 'L', '\="\n"', '')]])) + end) + + it('with submatch() (TEST_4)', function() + execute('set magic&') + eq('a\\a', eval([[substitute('aAa', 'A', ]] .. + [['\=substitute(submatch(0), ".", "\\", "")', '')]])) + eq('b\\b', eval([[substitute('bBb', 'B', ]] .. + [['\=substitute(submatch(0), ".", "\\\\", "")', '')]])) + eq('c\rc', eval([[substitute('cCc', 'C', ]] .. + [['\=substitute(submatch(0), ".", "]]..'\r'..[[", "")', '')]])) + eq('d\rd', eval([[substitute('dDd', 'D', ]] .. + [['\=substitute(submatch(0), ".", "\\]]..'\r'..[[", "")', '')]])) + eq('e\\\re', eval([[substitute('eEe', 'E', ]] .. + [['\=substitute(submatch(0), ".", "\\\\]]..'\r'..[[", "")', '')]])) + eq('f\rf', eval([[substitute('fFf', 'F', ]] .. + [['\=substitute(submatch(0), ".", "\\r", "")', '')]])) + eq('j\nj', eval([[substitute('jJj', 'J', ]] .. + [['\=substitute(submatch(0), ".", "\\n", "")', '')]])) + eq('k\rk', eval([[substitute('kKk', 'K', ]] .. + [['\=substitute(submatch(0), ".", "\r", "")', '')]])) + eq('l\nl', eval([[substitute('lLl', 'L', ]] .. + [['\=substitute(submatch(0), ".", "\n", "")', '')]])) + end) + + it('with submatch() (TEST_5)', function() + execute('set magic&') + eq('A123456789987654321', eval([[substitute('A123456789', ]] .. + [['A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] .. + [['\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . ]] .. + [[submatch(6) . submatch(5) . submatch(4) . submatch(3) . ]] .. + [[submatch(2) . submatch(1)', '')]])) + eq("[['A123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], " .. + "['2'], ['1']]", eval([[substitute('A123456789', ]] .. + [['A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] .. + [['\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), ]] .. + [[submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), ]] .. + [[submatch(3, 1), submatch(2, 1), submatch(1, 1)])', '')]])) + end) + + -- TEST_6 was about the 'cpoptions' flag / which was removed in pull request + -- #2943. + + it('with submatch or \\ze (TEST_7)', function() + execute('set magic&') + eq('A\rA', eval("substitute('A\rA', 'A.', '\\=submatch(0)', '')")) + eq('B\nB', eval([[substitute("B\nB", 'B.', '\=submatch(0)', '')]])) + eq("['B\n']B", + eval([[substitute("B\nB", 'B.', '\=string(submatch(0, 1))', '')]])) + eq('-abab', eval([[substitute('-bb', '\zeb', 'a', 'g')]])) + eq('c-cbcbc', eval([[substitute('-bb', '\ze', 'c', 'g')]])) + end) + + it('with \\zs and \\ze (TEST_10)', function() + execute('set magic&') + eq('a1a2a3a', eval([[substitute('123', '\zs', 'a', 'g')]])) + eq('aaa', eval([[substitute('123', '\zs.', 'a', 'g')]])) + eq('1a2a3a', eval([[substitute('123', '.\zs', 'a', 'g')]])) + eq('a1a2a3a', eval([[substitute('123', '\ze', 'a', 'g')]])) + eq('a1a2a3', eval([[substitute('123', '\ze.', 'a', 'g')]])) + eq('aaa', eval([[substitute('123', '.\ze', 'a', 'g')]])) + eq('aa2a3a', eval([[substitute('123', '1\|\ze', 'a', 'g')]])) + eq('1aaa', eval([[substitute('123', '1\zs\|[23]', 'a', 'g')]])) + end) +end) + +describe(':substitue', function() + before_each(clear) + + it('with \\ze and \\zs and confirmation dialog (TEST_8)', function() + insert([[ + ,,X + ,,Y + ,,Z]]) + execute('set magic&') + execute([[1s/\(^\|,\)\ze\(,\|X\)/\1N/g]]) + execute([[2s/\(^\|,\)\ze\(,\|Y\)/\1N/gc]]) + feed('a') -- For the dialog of the previous :s command. + execute([[3s/\(^\|,\)\ze\(,\|Z\)/\1N/gc]]) + feed('yy') -- For the dialog of the previous :s command. + expect([[ + N,,NX + N,,NY + N,,NZ]]) + end) + + it('with confirmation dialog (TEST_9)', function() + insert('xxx') + execute('set magic&') + execute('s/x/X/gc') + feed('yyq') -- For the dialog of the previous :s command. + expect('XXx') + end) +end) diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua index c387d7484c..0843506827 100644 --- a/test/functional/legacy/mapping_spec.lua +++ b/test/functional/legacy/mapping_spec.lua @@ -23,16 +23,27 @@ describe('mapping', function() execute('set langmap=+{ langnoremap') feed('o+<esc>') - -- expr mapping with langmap. + -- Insert mode expr mapping with langmap. execute('inoremap <expr> { "FAIL_iexplangmap"') feed('o+<esc>') + -- langmap should not get remapped in cmdline mode. + execute('cnoremap { FAIL_clangmap') + feed('o+<esc>') + execute('cunmap {') + + -- cmdline mode expr mapping with langmap. + execute('cnoremap <expr> { "FAIL_cexplangmap"') + feed('o+<esc>') + execute('cunmap {') -- Assert buffer contents. expect([[ test starts here: vim + + + + + +]]) end) end) diff --git a/test/functional/runtime/autoload/remote/define_spec.lua b/test/functional/provider/define_spec.lua index 9b97ed84d9..9b97ed84d9 100644 --- a/test/functional/runtime/autoload/remote/define_spec.lua +++ b/test/functional/provider/define_spec.lua diff --git a/test/functional/runtime/autoload/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua index 43889b7b2a..5be5390370 100644 --- a/test/functional/runtime/autoload/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -1,19 +1,19 @@ do - local proc = - io.popen([[python3 -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]]) + local proc = io.popen( + [[python3 -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]]) if proc:read() ~= 'ok' then - -- Don't run these tests if python3 is not available + pending( + 'python3 (or the python3 neovim module) is broken or missing', + function() end) return end end - local helpers = require('test.functional.helpers') local eval, command, feed = helpers.eval, helpers.command, helpers.feed local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert local expect, write_file = helpers.expect, helpers.write_file - describe('python3 commands and functions', function() before_each(function() clear() diff --git a/test/functional/runtime/autoload/provider/python_spec.lua b/test/functional/provider/python_spec.lua index e71a7a4309..ec1a853546 100644 --- a/test/functional/runtime/autoload/provider/python_spec.lua +++ b/test/functional/provider/python_spec.lua @@ -1,19 +1,19 @@ do - local proc = - io.popen([[python -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]]) + local proc = io.popen( + [[python -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]]) if proc:read() ~= 'ok' then - -- Don't run these tests if python is not available + pending( + 'python (or the python neovim module) is broken or missing', + function() end) return end end - local helpers = require('test.functional.helpers') local eval, command, feed = helpers.eval, helpers.command, helpers.feed local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert local expect, write_file = helpers.expect, helpers.write_file - describe('python commands and functions', function() before_each(function() clear() diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/shell/viml_system_spec.lua index 6e10715612..4985c24aec 100644 --- a/test/functional/shell/viml_system_spec.lua +++ b/test/functional/shell/viml_system_spec.lua @@ -186,7 +186,7 @@ describe('system()', function() describe("with a program that doesn't close stdout", function() if not xclip then - pending('skipped (missing xclip)') + pending('skipped (missing xclip)', function() end) else it('will exit properly after passing input', function() eq('', eval([[system('xclip -i -selection clipboard', 'clip-data')]])) @@ -365,7 +365,7 @@ describe('systemlist()', function() describe("with a program that doesn't close stdout", function() if not xclip then - pending('skipped (missing xclip)') + pending('skipped (missing xclip)', function() end) else it('will exit properly after passing input', function() eq({}, eval( diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index b72527e7b6..1a96cb4dba 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local nvim_dir, execute = helpers.nvim_dir, helpers.execute +local eq, eval = helpers.eq, helpers.eval describe('terminal window highlighting', function() @@ -161,3 +162,27 @@ describe('terminal window highlighting with custom palette', function() ]]) end) end) + +describe('synIDattr()', function() + local screen + + before_each(function() + clear() + screen = Screen.new(50, 7) + execute('highlight Normal ctermfg=1 guifg=#ff0000') + end) + + after_each(function() + screen:detach() + end) + + it('returns RGB number if GUI', function() + screen:attach(true) + eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")')) + end) + + it('returns color number if non-GUI', function() + screen:attach(false) + eq('1', eval('synIDattr(hlID("Normal"), "fg")')) + end) +end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 9635f6119c..1d616ed853 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -259,6 +259,13 @@ This is probably due to an indeterminism in the test. Try adding `wait()` (or even a separate `screen:expect(...)`) at a point of possible indeterminism, typically in between a `feed()` or `execute()` which is non- synchronous, and a synchronous api call. + +Note that sometimes a `wait` can trigger redraws and consequently generate more +indeterminism. If adding `wait` calls seems to increase the frequency of these +messages, try removing every `wait` call in the test. + +If everything else fails, use Screen:redraw_debug to help investigate what is + causing the problem. ]]) local tb = debug.traceback() local index = string.find(tb, '\n%s*%[C]') @@ -333,12 +340,9 @@ function Screen:_handle_mouse_off() self._mouse_enabled = false end -function Screen:_handle_insert_mode() - self._mode = 'insert' -end - -function Screen:_handle_normal_mode() - self._mode = 'normal' +function Screen:_handle_mode_change(mode) + assert(mode == 'insert' or mode == 'replace' or mode == 'normal') + self._mode = mode end function Screen:_handle_set_scroll_region(top, bot, left, right) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index d57c1773b1..421c167300 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -63,6 +63,29 @@ describe('Screen', function() end end) end) + + it('has correct default title with unnamed file', function() + local expected = '[No Name] - NVIM' + execute('set title') + screen:wait(function() + local actual = screen.title + if actual ~= expected then + return 'Expected title to be "'..expected..'" but was "'..actual..'"' + end + end) + end) + + it('has correct default title with named file', function() + local expected = 'myfile (/mydir) - NVIM' + execute('set title') + execute('file /mydir/myfile') + screen:wait(function() + local actual = screen.title + if actual ~= expected then + return 'Expected title to be "'..expected..'" but was "'..actual..'"' + end + end) + end) end) describe(':set icon', function() @@ -488,7 +511,6 @@ describe('Screen', function() end) it('has minimum width/height values', function() - wait() screen:try_resize(1, 1) screen:expect([[ -- INS^ERT --| diff --git a/test/unit/fixtures/queue.c b/test/unit/fixtures/queue.c new file mode 100644 index 0000000000..bbb6274b21 --- /dev/null +++ b/test/unit/fixtures/queue.c @@ -0,0 +1,16 @@ +#include <string.h> +#include <stdlib.h> +#include "nvim/event/queue.h" +#include "queue.h" + + +void ut_queue_put(Queue *queue, const char *str) +{ + queue_put(queue, NULL, 1, str); +} + +const char *ut_queue_get(Queue *queue) +{ + Event event = queue_get(queue); + return event.argv[0]; +} diff --git a/test/unit/fixtures/queue.h b/test/unit/fixtures/queue.h new file mode 100644 index 0000000000..ae949c9f29 --- /dev/null +++ b/test/unit/fixtures/queue.h @@ -0,0 +1,4 @@ +#include "nvim/event/queue.h" + +void ut_queue_put(Queue *queue, const char *str); +const char *ut_queue_get(Queue *queue); diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 3d5c6bc885..9cca3ca244 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -19,7 +19,7 @@ require('bit') cimport('unistd.h') cimport('./src/nvim/os/shell.h') cimport('./src/nvim/option_defs.h') -cimport('./src/nvim/os/event.h') +cimport('./src/nvim/main.h') cimport('./src/nvim/fileio.h') local fs = cimport('./src/nvim/os/os.h') cppimport('sys/stat.h') @@ -32,6 +32,14 @@ local directory = nil local absolute_executable = nil local executable_name = nil +local function set_bit(number, to_set) + return bit.bor(number, to_set) +end + +local function unset_bit(number, to_unset) + return bit.band(number, (bit.bnot(to_unset))) +end + local function assert_file_exists(filepath) neq(nil, lfs.attributes(filepath)) end @@ -40,11 +48,24 @@ local function assert_file_does_not_exist(filepath) eq(nil, lfs.attributes(filepath)) end +local function os_setperm(filename, perm) + return fs.os_setperm((to_cstr(filename)), perm) +end + +local function os_getperm(filename) + local perm = fs.os_getperm((to_cstr(filename))) + return tonumber(perm) +end + describe('fs function', function() + local orig_test_file_perm setup(function() lfs.mkdir('unit-test-directory'); + io.open('unit-test-directory/test.file', 'w').close() + orig_test_file_perm = os_getperm('unit-test-directory/test.file') + io.open('unit-test-directory/test_2.file', 'w').close() lfs.link('test.file', 'unit-test-directory/test_link.file', true) -- Since the tests are executed, they are called by an executable. We use @@ -188,6 +209,10 @@ describe('fs function', function() end) describe('file permissions', function() + before_each(function() + os_setperm('unit-test-directory/test.file', orig_test_file_perm) + end) + local function os_getperm(filename) local perm = fs.os_getperm((to_cstr(filename))) return tonumber(perm) @@ -208,6 +233,10 @@ describe('fs function', function() return fs.os_file_is_readonly((to_cstr(filename))) end + local function os_file_is_readable(filename) + return fs.os_file_is_readable((to_cstr(filename))) + end + local function os_file_is_writable(filename) return fs.os_file_is_writable((to_cstr(filename))) end @@ -216,14 +245,6 @@ describe('fs function', function() return 0 ~= (bit.band(number, check_bit)) end - local function set_bit(number, to_set) - return bit.bor(number, to_set) - end - - local function unset_bit(number, to_unset) - return bit.band(number, (bit.bnot(to_unset))) - end - describe('os_getperm', function() it('returns -1 when the given file does not exist', function() eq(-1, (os_getperm('non-existing-file'))) @@ -270,7 +291,7 @@ describe('fs function', function() -- Some systems may not have `id` utility. if (os.execute('id -G > /dev/null 2>&1') ~= 0) then - pending('skipped (missing `id` utility)') + pending('skipped (missing `id` utility)', function() end) else it('owner of a file may change the group of the file to any group of which that owner is a member', function() local file_gid = lfs.attributes(filename, 'gid') @@ -296,7 +317,7 @@ describe('fs function', function() -- On Windows `os_fchown` always returns 0 -- because `uv_fs_chown` is no-op on this platform. if (ffi.os == 'Windows' or ffi.C.geteuid() == 0) then - pending('skipped (os_fchown is no-op on Windows)') + pending('skipped (os_fchown is no-op on Windows)', function() end) else it('returns nonzero if process has not enough permissions', function() -- chown to root @@ -322,16 +343,35 @@ describe('fs function', function() end) end) + describe('os_file_is_readable', function() + it('returns false if the file is not readable', function() + local perm = os_getperm('unit-test-directory/test.file') + perm = unset_bit(perm, ffi.C.kS_IRUSR) + perm = unset_bit(perm, ffi.C.kS_IRGRP) + perm = unset_bit(perm, ffi.C.kS_IROTH) + eq(OK, (os_setperm('unit-test-directory/test.file', perm))) + eq(false, os_file_is_readable('unit-test-directory/test.file')) + end) + + it('returns false if the file does not exist', function() + eq(false, os_file_is_readable( + 'unit-test-directory/what_are_you_smoking.gif')) + end) + + it('returns true if the file is readable', function() + eq(true, os_file_is_readable( + 'unit-test-directory/test.file')) + end) + end) + describe('os_file_is_writable', function() it('returns 0 if the file is readonly', function() local perm = os_getperm('unit-test-directory/test.file') - local perm_orig = perm perm = unset_bit(perm, ffi.C.kS_IWUSR) perm = unset_bit(perm, ffi.C.kS_IWGRP) perm = unset_bit(perm, ffi.C.kS_IWOTH) eq(OK, (os_setperm('unit-test-directory/test.file', perm))) eq(0, os_file_is_writable('unit-test-directory/test.file')) - eq(OK, (os_setperm('unit-test-directory/test.file', perm_orig))) end) it('returns 1 if the file is writable', function() @@ -486,6 +526,16 @@ describe('fs function', function() return fs.os_rmdir(to_cstr(path)) end + local function os_mkdir_recurse(path, mode) + local failed_str = ffi.new('char *[1]', {nil}) + local ret = fs.os_mkdir_recurse(path, mode, failed_str) + local str = failed_str[0] + if str ~= nil then + str = ffi.string(str) + end + return ret, str + end + describe('os_mkdir', function() it('returns non-zero when given an already existing directory', function() local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR @@ -501,6 +551,59 @@ describe('fs function', function() end) end) + describe('os_mkdir_recurse', function() + it('returns zero when given an already existing directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse('unit-test-directory', mode) + eq(0, ret) + eq(nil, failed_str) + end) + + it('fails to create a directory where there is a file', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('fails to create a directory where there is a file in path', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file/test', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('succeeds to create a directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + + it('succeeds to create a directory tree', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse/1/2/3', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2/3')) + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2/3') + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2') + lfs.rmdir('unit-test-directory/new-dir-recurse/1') + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + end) + describe('os_rmdir', function() it('returns non_zero when given a non-existing directory', function() neq(0, (os_rmdir('non-existing-directory'))) diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua index 91d807da0b..91123bfd58 100644 --- a/test/unit/os/shell_spec.lua +++ b/test/unit/os/shell_spec.lua @@ -14,7 +14,7 @@ local helpers = require('test.unit.helpers') local shell = helpers.cimport( './src/nvim/os/shell.h', './src/nvim/option_defs.h', - './src/nvim/os/event.h', + './src/nvim/main.h', './src/nvim/misc1.h' ) local ffi, eq, neq = helpers.ffi, helpers.eq, helpers.neq diff --git a/test/unit/queue_spec.lua b/test/unit/queue_spec.lua new file mode 100644 index 0000000000..9326c1cad6 --- /dev/null +++ b/test/unit/queue_spec.lua @@ -0,0 +1,123 @@ +local helpers = require("test.unit.helpers") + +local ffi = helpers.ffi +local eq = helpers.eq + +local queue = helpers.cimport("./test/unit/fixtures/queue.h") + +describe('queue', function() + local parent, child1, child2, child3 + + local function put(q, str) + queue.ut_queue_put(q, str) + end + + local function get(q) + return ffi.string(queue.ut_queue_get(q)) + end + + local function free(q) + queue.queue_free(q) + end + + before_each(function() + parent = queue.queue_new_parent(ffi.NULL, ffi.NULL) + child1 = queue.queue_new_child(parent) + child2 = queue.queue_new_child(parent) + child3 = queue.queue_new_child(parent) + put(child1, 'c1i1') + put(child1, 'c1i2') + put(child2, 'c2i1') + put(child1, 'c1i3') + put(child2, 'c2i2') + put(child2, 'c2i3') + put(child2, 'c2i4') + put(child3, 'c3i1') + put(child3, 'c3i2') + end) + + it('removing from parent removes from child', function() + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + end) + + it('removing from child removes from parent', function() + eq('c2i1', get(child2)) + eq('c2i2', get(child2)) + eq('c1i1', get(child1)) + eq('c1i2', get(parent)) + eq('c1i3', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + end) + + it('removing from child at the beginning of parent', function() + eq('c1i1', get(child1)) + eq('c1i2', get(child1)) + eq('c2i1', get(parent)) + end) + + it('removing from parent after get from parent and put to child', function() + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + eq('c3i1', get(parent)) + put(child1, 'c1i11') + put(child1, 'c1i22') + eq('c3i2', get(parent)) + eq('c1i11', get(parent)) + eq('c1i22', get(parent)) + end) + + it('removing from parent after get and put to child', function() + eq('c1i1', get(child1)) + eq('c1i2', get(child1)) + eq('c2i1', get(child2)) + eq('c1i3', get(child1)) + eq('c2i2', get(child2)) + eq('c2i3', get(child2)) + eq('c2i4', get(child2)) + eq('c3i1', get(child3)) + eq('c3i2', get(parent)) + put(child1, 'c1i11') + put(child2, 'c2i11') + put(child1, 'c1i12') + eq('c2i11', get(child2)) + eq('c1i11', get(parent)) + eq('c1i12', get(parent)) + end) + + it('put after removing from child at the end of parent', function() + eq('c3i1', get(child3)) + eq('c3i2', get(child3)) + put(child1, 'c1i11') + put(child2, 'c2i11') + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + eq('c1i11', get(parent)) + eq('c2i11', get(parent)) + end) + + it('removes from parent queue when child is freed', function() + free(child2) + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c1i3', get(parent)) + eq('c3i1', get(child3)) + eq('c3i2', get(child3)) + end) +end) |
