diff options
Diffstat (limited to 'test')
38 files changed, 2622 insertions, 103 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 716bd88242..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') @@ -253,8 +267,68 @@ describe('clipboard usage', function() feed("viwp") eq({{'visual'}, 'v'}, eval("g:test_clip['*']")) expect("indeed clipboard") + + -- explicit "* should do the same + execute("let g:test_clip['*'] = [['star'], 'c']") + feed('viw"*p') + eq({{'clipboard'}, 'v'}, eval("g:test_clip['*']")) + 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() @@ -295,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() @@ -329,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/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua index 21176f1845..f4911cd3e8 100644 --- a/test/functional/ex_cmds/wviminfo_spec.lua +++ b/test/functional/ex_cmds/wviminfo_spec.lua @@ -1,7 +1,7 @@ local helpers, lfs = require('test.functional.helpers'), require('lfs') -local clear, execute, eq, neq, spawn, nvim_prog, set_session, wait = - helpers.clear, helpers.execute, helpers.eq, helpers.neq, helpers.spawn, - helpers.nvim_prog, helpers.set_session, helpers.wait +local clear, execute, eq, neq, spawn, nvim_prog, set_session, wait, write_file + = helpers.clear, helpers.execute, helpers.eq, helpers.neq, helpers.spawn, + helpers.nvim_prog, helpers.set_session, helpers.wait, helpers.write_file describe(':wviminfo', function() local viminfo_file = 'wviminfo_test' @@ -33,10 +33,7 @@ describe(':wviminfo', function() local text = 'wviminfo test' -- Create a dummy file - local fp = io.open(viminfo_file, 'w') - fp:write(text) - fp:flush() - fp:close() + write_file(viminfo_file, text) -- sanity check eq(text, io.open(viminfo_file):read()) 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 3d02aa7fdd..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'} @@ -207,12 +206,17 @@ local function execute(...) end end +-- Dedent the given text and write it to the file name. +local function write_file(name, text) + local file = io.open(name, 'w') + file:write(dedent(text)) + file:flush() + file:close() +end + local function source(code) local tmpname = os.tmpname() - local tmpfile = io.open(tmpname, "w") - tmpfile:write(code) - tmpfile:flush() - tmpfile:close() + write_file(tmpname, code) nvim_command('source '..tmpname) os.remove(tmpname) end @@ -285,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, @@ -315,5 +341,7 @@ return { curtab = curtab, curbuf_contents = curbuf_contents, wait = wait, - set_session = set_session + set_session = set_session, + write_file = write_file, + rmdir = rmdir } diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua index 1ba858251c..7085d61cc7 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/job/job_spec.lua @@ -1,11 +1,11 @@ local helpers = require('test.functional.helpers') -local clear, nvim, eq, neq, ok, expect, eval, next_msg, run, stop, session - = helpers.clear, helpers.nvim, helpers.eq, helpers.neq, helpers.ok, - helpers.expect, helpers.eval, helpers.next_message, helpers.run, - helpers.stop, helpers.session -local nvim_dir, insert, feed = helpers.nvim_dir, helpers.insert, helpers.feed -local source, execute, wait = helpers.source, helpers.execute, helpers.wait +local clear, eq, eval, execute, expect, feed, insert, neq, next_msg, nvim, + nvim_dir, ok, run, session, source, stop, wait, write_file = helpers.clear, + helpers.eq, helpers.eval, helpers.execute, helpers.expect, helpers.feed, + helpers.insert, helpers.neq, helpers.next_message, helpers.nvim, + helpers.nvim_dir, helpers.ok, helpers.run, helpers.session, helpers.source, + helpers.stop, helpers.wait, helpers.write_file describe('jobs', function() @@ -64,9 +64,7 @@ describe('jobs', function() it('preserves NULs', function() -- Make a file with NULs in it. local filename = os.tmpname() - local file = io.open(filename, "w") - file:write("abc\0def\n") - file:close() + write_file(filename, "abc\0def\n") nvim('command', "let j = jobstart(['cat', '"..filename.."'], g:job_opts)") eq({'notification', 'stdout', {0, {'abc\ndef', ''}}}, next_msg()) @@ -306,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 d30f83dc6d..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 os = require('os') +local write_file = helpers.write_file describe('exists() and has() functions', function() - setup(clear) - - it('is working', function() - + setup(function() + clear() -- Create a temporary script needed for the test. - local script = io.open('test60.vim', 'w') - script:write(helpers.dedent([=[ + write_file('test60.vim', [[ " Vim script for exists() function test " Script-local variables are checked here @@ -110,9 +107,14 @@ describe('exists() and has() functions', function() echo "FAILED" endif unlet str - ]=])) - script:flush() - script:close() + ]]) + 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 @@ -650,7 +652,7 @@ describe('exists() and has() functions', function() ]=]) -- Assert buffer contents. - expect([=[ + expect([[ #myagroup: 1 OK @@ -861,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/061_undo_tree_spec.lua b/test/functional/legacy/061_undo_tree_spec.lua index c911e2be47..8cc2a371bb 100644 --- a/test/functional/legacy/061_undo_tree_spec.lua +++ b/test/functional/legacy/061_undo_tree_spec.lua @@ -1,9 +1,10 @@ -- Tests for undo tree and :earlier and :later. local helpers = require('test.functional.helpers') -local feed, insert, source, eq, eval, clear, execute, expect, wait = - helpers.feed, helpers.insert, helpers.source, helpers.eq, helpers.eval, - helpers.clear, helpers.execute, helpers.expect, helpers.wait +local feed, insert, source, eq, eval, clear, execute, expect, wait, write_file + = helpers.feed, helpers.insert, helpers.source, helpers.eq, helpers.eval, + helpers.clear, helpers.execute, helpers.expect, helpers.wait, + helpers.write_file local function expect_empty_buffer() -- The space will be removed by helpers.dedent but is needed because dedent @@ -13,12 +14,6 @@ end local function expect_line(line) return eq(line, eval('getline(".")')) end -local function write_file(name, text) - local file = io.open(name, 'w') - file:write(text) - file:flush() - file:close() -end describe('undo tree:', function() before_each(clear) @@ -40,7 +35,7 @@ describe('undo tree:', function() write_file('Xtest', '\n123456789\n') -- `:earlier` and `:later` are (obviously) time-sensitive, so this test - -- sometimes fails if the system is under load. It is wrapped in a local + -- sometimes fails if the system is under load. It is wrapped in a local -- function to allow multiple attempts. local function test_earlier_later() clear() 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 6e6ba96f81..5be5390370 100644 --- a/test/functional/runtime/autoload/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -1,18 +1,18 @@ 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 = helpers.expect - +local expect, write_file = helpers.expect, helpers.write_file describe('python3 commands and functions', function() before_each(function() @@ -46,9 +46,7 @@ describe('python3 commands and functions', function() it('py3file', function() local fname = 'py3file.py' - local F = io.open(fname, 'w') - F:write('vim.command("let set_by_py3file = 123")') - F:close() + write_file(fname, 'vim.command("let set_by_py3file = 123")') command('py3file py3file.py') eq(123, eval('g:set_by_py3file')) os.remove(fname) diff --git a/test/functional/runtime/autoload/provider/python_spec.lua b/test/functional/provider/python_spec.lua index 5398d668bf..ec1a853546 100644 --- a/test/functional/runtime/autoload/provider/python_spec.lua +++ b/test/functional/provider/python_spec.lua @@ -1,18 +1,18 @@ 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 = helpers.expect - +local expect, write_file = helpers.expect, helpers.write_file describe('python commands and functions', function() before_each(function() @@ -46,9 +46,7 @@ describe('python commands and functions', function() it('pyfile', function() local fname = 'pyfile.py' - local F = io.open(fname, 'w') - F:write('vim.command("let set_by_pyfile = 123")') - F:close() + write_file(fname, 'vim.command("let set_by_pyfile = 123")') command('pyfile pyfile.py') eq(123, eval('g:set_by_pyfile')) os.remove(fname) 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/buffer_spec.lua b/test/unit/buffer_spec.lua index 5244c2af86..e0e2b827e9 100644 --- a/test/unit/buffer_spec.lua +++ b/test/unit/buffer_spec.lua @@ -3,8 +3,6 @@ local helpers = require("test.unit.helpers") local to_cstr = helpers.to_cstr local eq = helpers.eq -helpers.vim_init() - local buffer = helpers.cimport("./src/nvim/buffer.h") local window = helpers.cimport("./src/nvim/window.h") local option = helpers.cimport("./src/nvim/option.h") 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/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c new file mode 100644 index 0000000000..d587d6b054 --- /dev/null +++ b/test/unit/fixtures/rbuffer.c @@ -0,0 +1,28 @@ +#include "nvim/rbuffer.h" +#include "rbuffer.h" + + +void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb) +{ + RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) { + cb(rptr, rcnt); + rbuffer_consumed(buf, rcnt); + } +} + +void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb) +{ + RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { + cb(wptr, wcnt); + rbuffer_produced(buf, wcnt); + } +} +void ut_rbuffer_each(RBuffer *buf, each_cb cb) +{ + RBUFFER_EACH(buf, c, i) cb(c, i); +} + +void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb) +{ + RBUFFER_EACH_REVERSE(buf, c, i) cb(c, i); +} diff --git a/test/unit/fixtures/rbuffer.h b/test/unit/fixtures/rbuffer.h new file mode 100644 index 0000000000..640092c627 --- /dev/null +++ b/test/unit/fixtures/rbuffer.h @@ -0,0 +1,9 @@ +#include "nvim/rbuffer.h" + +typedef void(*each_ptr_cb)(char *ptr, size_t cnt); +typedef void(*each_cb)(char c, size_t i); + +void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb); +void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb); +void ut_rbuffer_each(RBuffer *buf, each_cb cb); +void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb); diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 708e7a94ab..5bcc661226 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -136,15 +136,11 @@ end -- initialize some global variables, this is still necessary to unit test -- functions that rely on global state. -local function vim_init() - if vim_init_called ~= nil then - return - end +do local main = cimport('./src/nvim/main.h') local time = cimport('./src/nvim/os/time.h') time.time_init() main.early_init() - vim_init_called = true end -- C constants. @@ -167,7 +163,6 @@ return { lib = libnvim, cstr = cstr, to_cstr = to_cstr, - vim_init = vim_init, NULL = NULL, OK = OK, FAIL = FAIL diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua index 9d936c2564..8e18c599d9 100644 --- a/test/unit/os/env_spec.lua +++ b/test/unit/os/env_spec.lua @@ -12,9 +12,6 @@ local NULL = helpers.NULL require('lfs') --- Needed because expand_env_esc uses the char table -helpers.vim_init() - local env = cimport('./src/nvim/os/os.h') describe('env function', function() diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 3d5c6bc885..f7f0cba951 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') @@ -270,7 +270,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 +296,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 @@ -486,6 +486,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 +511,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) diff --git a/test/unit/rbuffer_spec.lua b/test/unit/rbuffer_spec.lua new file mode 100644 index 0000000000..89136410d3 --- /dev/null +++ b/test/unit/rbuffer_spec.lua @@ -0,0 +1,350 @@ +local helpers = require("test.unit.helpers") + +local ffi = helpers.ffi +local eq = helpers.eq +local cstr = helpers.cstr +local to_cstr = helpers.to_cstr + +local rbuffer = helpers.cimport("./test/unit/fixtures/rbuffer.h") + +describe('rbuffer functions', function() + local capacity = 16 + local rbuf + + local function inspect() + return ffi.string(rbuf.start_ptr, capacity) + end + + local function write(str) + local buf = to_cstr(str) + return rbuffer.rbuffer_write(rbuf, buf, #str) + end + + local function read(len) + local buf = cstr(len) + len = rbuffer.rbuffer_read(rbuf, buf, len) + return ffi.string(buf, len) + end + + local function get(idx) + return ffi.string(rbuffer.rbuffer_get(rbuf, idx), 1) + end + + before_each(function() + rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free) + -- fill the internal buffer with the character '0' to simplify inspecting + ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity) + end) + + describe('RBUFFER_UNTIL_FULL', function() + local chunks + + local function collect_write_chunks() + rbuffer.ut_rbuffer_each_write_chunk(rbuf, function(wptr, wcnt) + table.insert(chunks, ffi.string(wptr, wcnt)) + end) + end + + before_each(function() + chunks = {} + end) + + describe('with empty buffer in one contiguous chunk', function() + it('is called once with the empty chunk', function() + collect_write_chunks() + eq({'0000000000000000'}, chunks) + end) + end) + + describe('with partially empty buffer in one contiguous chunk', function() + before_each(function() + write('string') + end) + + it('is called once with the empty chunk', function() + collect_write_chunks() + eq({'0000000000'}, chunks) + end) + end) + + describe('with filled buffer in one contiguous chunk', function() + before_each(function() + write('abcdefghijklmnopq') + end) + + it('is not called', function() + collect_write_chunks() + eq({}, chunks) + end) + end) + + describe('with buffer partially empty in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(8) + end) + + it('is called twice with each filled chunk', function() + collect_write_chunks() + eq({'000000', '12345678'}, chunks) + end) + end) + + describe('with buffer empty in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + end) + + it('is called twice with each filled chunk', function() + collect_write_chunks() + eq({'00000000', '12345678'}, chunks) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + write('abcdefghijklmnopq') + end) + + it('is not called', function() + collect_write_chunks() + eq({}, chunks) + end) + end) + end) + + describe('RBUFFER_UNTIL_EMPTY', function() + local chunks + + local function collect_read_chunks() + rbuffer.ut_rbuffer_each_read_chunk(rbuf, function(rptr, rcnt) + table.insert(chunks, ffi.string(rptr, rcnt)) + end) + end + + before_each(function() + chunks = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_read_chunks() + eq({}, chunks) + end) + end) + + describe('with partially filled buffer in one contiguous chunk', function() + before_each(function() + write('string') + end) + + it('is called once with the filled chunk', function() + collect_read_chunks() + eq({'string'}, chunks) + end) + end) + + describe('with filled buffer in one contiguous chunk', function() + before_each(function() + write('abcdefghijklmnopq') + end) + + it('is called once with the filled chunk', function() + collect_read_chunks() + eq({'abcdefghijklmnop'}, chunks) + end) + end) + + describe('with buffer partially filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('is called twice with each filled chunk', function() + collect_read_chunks() + eq({'long s', 'tring'}, chunks) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + write('abcdefghijklmnopq') + end) + + it('is called twice with each filled chunk', function() + collect_read_chunks() + eq({'abcdefgh', 'ijklmnop'}, chunks) + end) + end) + end) + + describe('RBUFFER_EACH', function() + local chars + + local function collect_chars() + rbuffer.ut_rbuffer_each(rbuf, function(c, i) + table.insert(chars, {string.char(c), tonumber(i)}) + end) + end + before_each(function() + chars = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_chars() + eq({}, chars) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('collects each character and index', function() + collect_chars() + eq({{'l', 0}, {'o', 1}, {'n', 2}, {'g', 3}, {' ', 4}, {'s', 5}, + {'t', 6}, {'r', 7}, {'i', 8}, {'n', 9}, {'g', 10}}, chars) + end) + end) + end) + + describe('RBUFFER_EACH_REVERSE', function() + local chars + + local function collect_chars() + rbuffer.ut_rbuffer_each_reverse(rbuf, function(c, i) + table.insert(chars, {string.char(c), tonumber(i)}) + end) + end + before_each(function() + chars = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_chars() + eq({}, chars) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('collects each character and index', function() + collect_chars() + eq({{'g', 10}, {'n', 9}, {'i', 8}, {'r', 7}, {'t', 6}, {'s', 5}, + {' ', 4}, {'g', 3}, {'n', 2}, {'o', 1}, {'l', 0}}, chars) + end) + end) + end) + + describe('rbuffer_cmp', function() + local function cmp(str) + local rv = rbuffer.rbuffer_cmp(rbuf, to_cstr(str), #str) + if rv == 0 then + return 0 + else + return rv / math.abs(rv) + end + end + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('compares the common longest sequence', function() + eq(0, cmp('long string')) + eq(0, cmp('long strin')) + eq(-1, cmp('long striM')) + eq(1, cmp('long strio')) + eq(0, cmp('long')) + eq(-1, cmp('lonG')) + eq(1, cmp('lonh')) + end) + end) + + describe('with empty buffer', function() + it('returns 0 since no characters are compared', function() + eq(0, cmp('')) + end) + end) + end) + + describe('rbuffer_write', function() + it('fills the internal buffer and returns the write count', function() + eq(12, write('short string')) + eq('short string0000', inspect()) + end) + + it('wont write beyond capacity', function() + eq(16, write('very very long string')) + eq('very very long s', inspect()) + end) + end) + + describe('rbuffer_read', function() + it('reads what was previously written', function() + write('to read') + eq('to read', read(20)) + end) + + it('reads nothing if the buffer is empty', function() + eq('', read(20)) + write('empty') + eq('empty', read(20)) + eq('', read(20)) + end) + end) + + describe('rbuffer_get', function() + it('fetch the pointer at offset, wrapping if required', function() + write('1234567890') + read(10) + write('long string') + eq('l', get(0)) + eq('o', get(1)) + eq('n', get(2)) + eq('g', get(3)) + eq(' ', get(4)) + eq('s', get(5)) + eq('t', get(6)) + eq('r', get(7)) + eq('i', get(8)) + eq('n', get(9)) + eq('g', get(10)) + end) + end) + + describe('wrapping behavior', function() + it('writing/reading wraps across the end of the internal buffer', function() + write('1234567890') + eq('1234', read(4)) + eq('5678', read(4)) + write('987654321') + eq('3214567890987654', inspect()) + eq('90987654321', read(20)) + eq('', read(4)) + write('abcdefghijklmnopqrs') + eq('nopabcdefghijklm', inspect()) + eq('abcdefghijklmnop', read(20)) + end) + end) +end) diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua index 6484a98b8f..e558ff04c8 100644 --- a/test/unit/tempfile_spec.lua +++ b/test/unit/tempfile_spec.lua @@ -4,8 +4,6 @@ local helpers = require 'test.unit.helpers' local os = helpers.cimport './src/nvim/os/os.h' local tempfile = helpers.cimport './src/nvim/tempfile.h' -helpers.vim_init() - describe('tempfile related functions', function() after_each(function() tempfile.vim_deltempdir() |
