diff options
Diffstat (limited to 'test')
20 files changed, 1683 insertions, 27 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index f4a9ddc698..9c9759adf6 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -144,15 +144,23 @@ describe('vim_* functions', function() describe('replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() - eq(helpers.nvim('replace_termcodes', '\128', true, true, true), '\128\254X') + eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true)) end) - it('leaves non K_SPECIAL string unchanged', function() - eq(helpers.nvim('replace_termcodes', 'abc', true, true, true), 'abc') + it('leaves non-K_SPECIAL string unchanged', function() + eq('abc', helpers.nvim('replace_termcodes', 'abc', true, true, true)) end) it('converts <expressions>', function() - eq(helpers.nvim('replace_termcodes', '<Leader>', true, true, true), '\\') + eq('\\', helpers.nvim('replace_termcodes', '<Leader>', true, true, true)) + end) + + it('converts <LeftMouse> to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function() + -- K_SPECIAL KS_EXTRA KE_LEFTMOUSE + -- 0x80 0xfd 0x2c + -- 128 253 44 + eq('\128\253\44', helpers.nvim('replace_termcodes', + '<LeftMouse>', true, true, true)) end) end) diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua index 0961340e61..4de3f039c1 100644 --- a/test/functional/autocmd/termclose_spec.lua +++ b/test/functional/autocmd/termclose_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, execute, feed, nvim, nvim_dir = helpers.clear, helpers.execute, helpers.feed, helpers.nvim, helpers.nvim_dir +local eval, eq = helpers.eval, helpers.eq describe('TermClose event', function() local screen @@ -25,4 +26,19 @@ describe('TermClose event', function() TermClose works! | ]]) end) + + it('reports the correct <abuf>', function() + execute('set hidden') + execute('autocmd TermClose * let g:abuf = expand("<abuf>")') + execute('edit foo') + execute('edit bar') + eq(2, eval('bufnr("%")')) + execute('terminal') + feed('<c-\\><c-n>') + eq(3, eval('bufnr("%")')) + execute('buffer 1') + eq(1, eval('bufnr("%")')) + execute('3bdelete!') + eq('3', eval('g:abuf')) + end) end) diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua new file mode 100644 index 0000000000..965b19581a --- /dev/null +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -0,0 +1,216 @@ +local helpers = require('test.functional.helpers') +local clear, eval, eq, insert = helpers.clear, helpers.eval, helpers.eq, helpers.insert +local feed, execute, expect, command = helpers.feed, helpers.execute, helpers.expect, helpers.command +local curbufmeths, funcs, neq = helpers.curbufmeths, helpers.funcs, helpers.neq + +describe('TextYankPost', function() + before_each(function() + clear() + + -- emulate the clipboard so system clipboard isn't affected + execute('let &rtp = "test/functional/fixtures,".&rtp') + + execute('let g:count = 0') + execute('autocmd TextYankPost * let g:event = copy(v:event)') + execute('autocmd TextYankPost * let g:count += 1') + + curbufmeths.set_line_slice(0, -1, true, true, { + 'foo\0bar', + 'baz text', + }) + end) + + it('is executed after yank and handles register types', function() + feed('yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + eq(1, eval('g:count')) + + -- v:event is cleared after the autocommand is done + eq({}, eval('v:event')) + + feed('+yw') + eq({ + operator = 'y', + regcontents = { 'baz ' }, + regname = '', + regtype = 'v' + }, eval('g:event')) + eq(2, eval('g:count')) + + feed('<c-v>eky') + eq({ + operator = 'y', + regcontents = { 'foo', 'baz' }, + regname = '', + regtype = "\0223" -- ^V + block width + }, eval('g:event')) + eq(3, eval('g:count')) + end) + + it('makes v:event immutable', function() + feed('yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + + execute('set debug=msg') + -- the regcontents should not be changed without copy. + local status, err = pcall(command,'call extend(g:event.regcontents, ["more text"])') + eq(status,false) + neq(nil, string.find(err, ':E742:')) + + -- can't mutate keys inside the autocommand + execute('autocmd! TextYankPost * let v:event.regcontents = 0') + status, err = pcall(command,'normal yy') + eq(status,false) + neq(nil, string.find(err, ':E46:')) + + -- can't add keys inside the autocommand + execute('autocmd! TextYankPost * let v:event.mykey = 0') + status, err = pcall(command,'normal yy') + eq(status,false) + neq(nil, string.find(err, ':E742:')) + end) + + it('is not invoked recursively', function() + execute('autocmd TextYankPost * normal "+yy') + feed('yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + eq(1, eval('g:count')) + eq({ 'foo\nbar' }, funcs.getreg('+',1,1)) + end) + + it('is executed after delete and change', function() + feed('dw') + eq({ + operator = 'd', + regcontents = { 'foo' }, + regname = '', + regtype = 'v' + }, eval('g:event')) + eq(1, eval('g:count')) + + feed('dd') + eq({ + operator = 'd', + regcontents = { '\nbar' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + eq(2, eval('g:count')) + + feed('cwspam<esc>') + eq({ + operator = 'c', + regcontents = { 'baz' }, + regname = '', + regtype = 'v' + }, eval('g:event')) + eq(3, eval('g:count')) + end) + + it('is not executed after black-hole operation', function() + feed('"_dd') + eq(0, eval('g:count')) + + feed('"_cwgood<esc>') + eq(0, eval('g:count')) + + expect([[ + good text]]) + feed('"_yy') + eq(0, eval('g:count')) + + execute('delete _') + eq(0, eval('g:count')) + end) + + it('gives the correct register name', function() + feed('$"byiw') + eq({ + operator = 'y', + regcontents = { 'bar' }, + regname = 'b', + regtype = 'v' + }, eval('g:event')) + + feed('"*yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '*', + regtype = 'V' + }, eval('g:event')) + + execute("set clipboard=unnamed") + + -- regname still shows the name the user requested + feed('yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + + feed('"*yy') + eq({ + operator = 'y', + regcontents = { 'foo\nbar' }, + regname = '*', + regtype = 'V' + }, eval('g:event')) + end) + + it('works with Ex commands', function() + execute('1delete +') + eq({ + operator = 'd', + regcontents = { 'foo\nbar' }, + regname = '+', + regtype = 'V' + }, eval('g:event')) + eq(1, eval('g:count')) + + execute('yank') + eq({ + operator = 'y', + regcontents = { 'baz text' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + eq(2, eval('g:count')) + + execute('normal yw') + eq({ + operator = 'y', + regcontents = { 'baz ' }, + regname = '', + regtype = 'v' + }, eval('g:event')) + eq(3, eval('g:count')) + + execute('normal! dd') + eq({ + operator = 'd', + regcontents = { 'baz text' }, + regname = '', + regtype = 'V' + }, eval('g:event')) + eq(4, eval('g:count')) + end) + +end) diff --git a/test/functional/eval/operators_spec.lua b/test/functional/eval/operators_spec.lua new file mode 100644 index 0000000000..bc9a17935c --- /dev/null +++ b/test/functional/eval/operators_spec.lua @@ -0,0 +1,28 @@ +local helpers = require('test.functional.helpers') +local eq = helpers.eq +local eval = helpers.eval +local clear = helpers.clear + +describe('Division operator', function() + before_each(clear) + + it('returns infinity on {positive}/0.0', function() + eq('str2float(\'inf\')', eval('string(1.0/0.0)')) + eq('str2float(\'inf\')', eval('string(1.0e-100/0.0)')) + eq('str2float(\'inf\')', eval('string(1.0e+100/0.0)')) + eq('str2float(\'inf\')', eval('string((1.0/0.0)/0.0)')) + end) + + it('returns -infinity on {negative}/0.0', function() + eq('-str2float(\'inf\')', eval('string((-1.0)/0.0)')) + eq('-str2float(\'inf\')', eval('string((-1.0e-100)/0.0)')) + eq('-str2float(\'inf\')', eval('string((-1.0e+100)/0.0)')) + eq('-str2float(\'inf\')', eval('string((-1.0/0.0)/0.0)')) + end) + + it('returns NaN on 0.0/0.0', function() + eq('str2float(\'nan\')', eval('string(0.0/0.0)')) + eq('str2float(\'nan\')', eval('string(-(0.0/0.0))')) + eq('str2float(\'nan\')', eval('string((-0.0)/0.0)')) + end) +end) diff --git a/test/functional/eval/string_spec.lua b/test/functional/eval/string_spec.lua new file mode 100644 index 0000000000..f7f5dca70a --- /dev/null +++ b/test/functional/eval/string_spec.lua @@ -0,0 +1,175 @@ +local helpers = require('test.functional.helpers') +local clear = helpers.clear +local eq = helpers.eq +local command = helpers.command +local meths = helpers.meths +local eval = helpers.eval +local exc_exec = helpers.exc_exec +local redir_exec = helpers.redir_exec +local funcs = helpers.funcs +local write_file = helpers.write_file + +describe('string() function', function() + before_each(clear) + + describe('used to represent floating-point values', function() + it('dumps NaN values', function() + eq('str2float(\'nan\')', eval('string(str2float(\'nan\'))')) + end) + + it('dumps infinite values', function() + eq('str2float(\'inf\')', eval('string(str2float(\'inf\'))')) + eq('-str2float(\'inf\')', eval('string(str2float(\'-inf\'))')) + end) + + it('dumps regular values', function() + eq('1.5', funcs.string(1.5)) + eq('1.56e-20', funcs.string(1.56000e-020)) + eq('0.0', eval('string(0.0)')) + end) + + it('dumps values with at most six digits after the decimal point', + function() + eq('1.234568e-20', funcs.string(1.23456789123456789123456789e-020)) + eq('1.234568', funcs.string(1.23456789123456789123456789)) + end) + + it('dumps values with at most seven digits before the decimal point', + function() + eq('1234567.891235', funcs.string(1234567.89123456789123456789)) + eq('1.234568e7', funcs.string(12345678.9123456789123456789)) + end) + + it('dumps negative values', function() + eq('-1.5', funcs.string(-1.5)) + eq('-1.56e-20', funcs.string(-1.56000e-020)) + eq('-1.234568e-20', funcs.string(-1.23456789123456789123456789e-020)) + eq('-1.234568', funcs.string(-1.23456789123456789123456789)) + eq('-1234567.891235', funcs.string(-1234567.89123456789123456789)) + eq('-1.234568e7', funcs.string(-12345678.9123456789123456789)) + end) + end) + + describe('used to represent numbers', function() + it('dumps regular values', function() + eq('0', funcs.string(0)) + eq('-1', funcs.string(-1)) + eq('1', funcs.string(1)) + end) + + it('dumps large values', function() + eq('2147483647', funcs.string(2^31-1)) + eq('-2147483648', funcs.string(-2^31)) + end) + end) + + describe('used to represent strings', function() + it('dumps regular strings', function() + eq('\'test\'', funcs.string('test')) + end) + + it('dumps empty strings', function() + eq('\'\'', funcs.string('')) + end) + + it('dumps strings with \' inside', function() + eq('\'\'\'\'\'\'\'\'', funcs.string('\'\'\'')) + eq('\'a\'\'b\'\'\'\'\'', funcs.string('a\'b\'\'')) + eq('\'\'\'b\'\'\'\'d\'', funcs.string('\'b\'\'d')) + eq('\'a\'\'b\'\'c\'\'d\'', funcs.string('a\'b\'c\'d')) + end) + end) + + describe('used to represent funcrefs', function() + local fname = 'Xtest-functional-eval-string_spec-fref-script.vim' + + before_each(function() + write_file(fname, [[ + function Test1() + endfunction + + function s:Test2() + endfunction + + function g:Test3() + endfunction + + let g:Test2_f = function('s:Test2') + ]]) + command('source ' .. fname) + end) + + after_each(function() + os.remove(fname) + end) + + it('dumps references to built-in functions', function() + eq('function(\'function\')', eval('string(function("function"))')) + end) + + it('dumps references to user functions', function() + eq('function(\'Test1\')', eval('string(function("Test1"))')) + eq('function(\'g:Test3\')', eval('string(function("g:Test3"))')) + end) + + it('dumps references to script functions', function() + eq('function(\'<SNR>1_Test2\')', eval('string(Test2_f)')) + end) + end) + + describe('used to represent lists', function() + it('dumps empty list', function() + eq('[]', funcs.string({})) + end) + + it('dumps nested lists', function() + eq('[[[[[]]]]]', funcs.string({{{{{}}}}})) + end) + + it('dumps nested non-empty lists', function() + eq('[1, [[3, [[5], 4]], 2]]', funcs.string({1, {{3, {{5}, 4}}, 2}})) + end) + + it('errors when dumping recursive lists', function() + meths.set_var('l', {}) + eval('add(l, l)') + eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container', + exc_exec('echo string(l)')) + end) + + it('dumps recursive lists despite the error', function() + meths.set_var('l', {}) + eval('add(l, l)') + eq('\nE724: unable to correctly dump variable with self-referencing container\n[{E724@0}]', + redir_exec('echo string(l)')) + eq('\nE724: unable to correctly dump variable with self-referencing container\n[[{E724@1}]]', + redir_exec('echo string([l])')) + end) + end) + + describe('used to represent dictionaries', function() + it('dumps empty dictionary', function() + eq('{}', eval('string({})')) + end) + + it('dumps non-empty dictionary', function() + eq('{\'t\'\'est\': 1}', funcs.string({['t\'est']=1})) + end) + + it('errors when dumping recursive dictionaries', function() + meths.set_var('d', {d=1}) + eval('extend(d, {"d": d})') + eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container', + exc_exec('echo string(d)')) + end) + + it('dumps recursive dictionaries despite the error', function() + meths.set_var('d', {d=1}) + eval('extend(d, {"d": d})') + eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'d\': {E724@0}}', + redir_exec('echo string(d)')) + eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'out\': {\'d\': {E724@1}}}', + redir_exec('echo string({"out": d})')) + end) + end) +end) diff --git a/test/functional/eval/vvar_event_spec.lua b/test/functional/eval/vvar_event_spec.lua new file mode 100644 index 0000000000..bbac86524f --- /dev/null +++ b/test/functional/eval/vvar_event_spec.lua @@ -0,0 +1,15 @@ +local helpers = require('test.functional.helpers') +local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq +local command = helpers.command +describe('v:event', function() + before_each(clear) + it('is empty before any autocommand', function() + eq({}, eval('v:event')) + end) + + it('is immutable', function() + eq(false, pcall(command, 'let v:event = {}')) + eq(false, pcall(command, 'let v:event.mykey = {}')) + end) +end) + diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c index 5fa8a58049..d9ec254aff 100644 --- a/test/functional/fixtures/shell-test.c +++ b/test/functional/fixtures/shell-test.c @@ -1,25 +1,59 @@ -// A simple implementation of a shell for testing -// `termopen([&sh, &shcf, '{cmd'}])` and `termopen([&sh])`. -// -// If launched with no arguments, prints "ready $ ", otherwise prints -// "ready $ {cmd}\n". - #include <stdio.h> #include <string.h> +#include <stdint.h> + +static void help(void) +{ + puts("A simple implementation of a shell for testing termopen()."); + puts(""); + puts("Usage:"); + puts(" shell-test --help"); + puts(" Prints this help to stdout."); + puts(" shell-test"); + puts(" shell-test EXE"); + puts(" Prints \"ready $ \" to stderr."); + puts(" shell-test EXE \"prog args...\""); + puts(" Prints \"ready $ prog args...\\n\" to stderr."); + puts(" shell-test REP {byte} \"line line line\""); + puts(" Prints \"{lnr}: line line line\\n\" to stdout {byte} times."); + puts(" I.e. for `shell-test REP ab \"test\"'"); + puts(" 0: test"); + puts(" ..."); + puts(" 96: test"); + puts(" will be printed because byte `a' is equal to 97."); +} int main(int argc, char **argv) { - fprintf(stderr, "ready $ "); + if (argc == 2 && strcmp(argv[1], "--help") == 0) { + help(); + } - if (argc == 3) { - // argv should be {"terminal-test", "EXE", "prog args..."} - if (strcmp(argv[1], "EXE") != 0) { - fprintf(stderr, "first argument must be 'EXE'\n"); - return 2; + if (argc >= 2) { + if (strcmp(argv[1], "EXE") == 0) { + fprintf(stderr, "ready $ "); + if (argc >= 3) { + fprintf(stderr, "%s\n", argv[2]); + } + } else if (strcmp(argv[1], "REP") == 0) { + if (argc < 4) { + fprintf(stderr, "Not enough REP arguments\n"); + return 4; + } + uint8_t number = (uint8_t) *argv[2]; + for (uint8_t i = 0; i < number; i++) { + printf("%d: %s\n", (int) i, argv[3]); + } + } else { + fprintf(stderr, "Unknown first argument\n"); + return 3; } - - fprintf(stderr, "%s\n", argv[2]); + return 0; + } else if (argc == 1) { + fprintf(stderr, "ready $ "); + return 0; + } else { + fprintf(stderr, "Missing first argument\n"); + return 2; } - - return 0; } diff --git a/test/functional/legacy/003_cindent_spec.lua b/test/functional/legacy/003_cindent_spec.lua index 19694550f4..4b838eda1d 100644 --- a/test/functional/legacy/003_cindent_spec.lua +++ b/test/functional/legacy/003_cindent_spec.lua @@ -674,6 +674,13 @@ describe('cindent', function() { } + A::A(int a, int b) + : aa(a), + bb(b), + cc(c) + { + } + class CAbc : public BaseClass1, protected BaseClass2 @@ -919,6 +926,55 @@ describe('cindent', function() )foo"; } + { + int a[4] = { + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + }; + } + + { + a = b[2] + + 3; + } + + { + if (1) + /* aaaaa + * bbbbb + */ + a = 1; + } + + void func() + { + switch (foo) + { + case (bar): + if (baz()) + quux(); + break; + case (shmoo): + if (!bar) + { + } + case (foo1): + switch (bar) + { + case baz: + baz_f(); + break; + } + break; + default: + baz(); + baz(); + break; + } + } + /* end of AUTO */ ]=]) @@ -1580,6 +1636,13 @@ describe('cindent', function() { } + A::A(int a, int b) + : aa(a), + bb(b), + cc(c) + { + } + class CAbc : public BaseClass1, protected BaseClass2 @@ -1825,6 +1888,55 @@ describe('cindent', function() )foo"; } + { + int a[4] = { + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + }; + } + + { + a = b[2] + + 3; + } + + { + if (1) + /* aaaaa + * bbbbb + */ + a = 1; + } + + void func() + { + switch (foo) + { + case (bar): + if (baz()) + quux(); + break; + case (shmoo): + if (!bar) + { + } + case (foo1): + switch (bar) + { + case baz: + baz_f(); + break; + } + break; + default: + baz(); + baz(); + break; + } + } + /* end of AUTO */ ]=]) end) diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua new file mode 100644 index 0000000000..483e465cee --- /dev/null +++ b/test/functional/legacy/011_autocommands_spec.lua @@ -0,0 +1,230 @@ +-- Tests for autocommands +-- - FileWritePre writing a compressed file +-- - FileReadPost reading a compressed file +-- - BufNewFile reading a file template +-- - BufReadPre decompressing the file to be read +-- - FilterReadPre substituting characters in the temp file +-- - FilterReadPost substituting characters after filtering +-- - FileReadPre set options for decompression +-- - FileReadPost decompress the file +-- Note: This test is skipped if "gzip" is not available. +-- $GZIP is made empty, "-v" would cause trouble. +-- Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz" +-- being modified outside of Vim (noticed on Solaris). + +local helpers, lfs = require('test.functional.helpers'), require('lfs') +local clear, execute, expect, eq, neq, dedent, write_file, feed = + helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.neq, + helpers.dedent, helpers.write_file, helpers.feed + +local function has_gzip() + return os.execute('gzip --help >/dev/null 2>&1') == 0 +end + +local function prepare_gz_file(name, text) + write_file(name, text..'\n') + -- Compress the file with gzip. + os.execute('gzip --force '..name) + -- This should create the .gz file and delete the original. + neq(nil, lfs.attributes(name..'.gz')) + eq(nil, lfs.attributes(name)) +end + +describe('file reading, writing and bufnew and filter autocommands', function() + local text1 = dedent([[ + start of testfile + line 2 Abcdefghijklmnopqrstuvwxyz + line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 4 Abcdefghijklmnopqrstuvwxyz + line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 6 Abcdefghijklmnopqrstuvwxyz + line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 8 Abcdefghijklmnopqrstuvwxyz + line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 10 Abcdefghijklmnopqrstuvwxyz + end of testfile]]) + setup(function() + write_file('Xtest.c', [[ + /* + * Here is a new .c file + */ + ]]) + end) + before_each(clear) + teardown(function() + os.remove('Xtestfile.gz') + os.remove('Xtest.c') + os.remove('test.out') + end) + + if not has_gzip() then + pending('skipped (missing `gzip` utility)', function() end) + else + + it('FileReadPost (using gzip)', function() + prepare_gz_file('Xtestfile', text1) + execute('let $GZIP = ""') + --execute('au FileChangedShell * echo "caught FileChangedShell"') + execute('set bin') + execute("au FileReadPost *.gz '[,']!gzip -d") + -- Read and decompress the testfile. + execute('$r Xtestfile.gz') + expect('\n'..text1) + end) + + it('BufReadPre, BufReadPost (using gzip)', function() + prepare_gz_file('Xtestfile', text1) + local gzip_data = io.open('Xtestfile.gz'):read('*all') + execute('let $GZIP = ""') + -- Setup autocommands to decompress before reading and re-compress afterwards. + execute("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))") + execute("au BufReadPre *.gz call rename(expand('<afile>:r'), expand('<afile>'))") + execute("au BufReadPost *.gz call rename(expand('<afile>'), expand('<afile>:r'))") + execute("au BufReadPost *.gz exe '!gzip ' . shellescape(expand('<afile>:r'))") + -- Edit compressed file. + execute('e! Xtestfile.gz') + -- Discard all prompts and messages. + feed('<C-L>') + -- Expect the decompressed file in the buffer. + expect(text1) + -- Expect the original file to be unchanged. + eq(gzip_data, io.open('Xtestfile.gz'):read('*all')) + end) + + it('FileReadPre, FileReadPost', function() + prepare_gz_file('Xtestfile', text1) + execute('au! FileReadPre *.gz exe "silent !gzip -d " . shellescape(expand("<afile>"))') + execute('au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))') + execute("au! FileReadPost *.gz '[,']s/l/L/") + -- Read compressed file. + execute('$r Xtestfile.gz') + -- Discard all prompts and messages. + feed('<C-L>') + expect([[ + + start of testfiLe + Line 2 Abcdefghijklmnopqrstuvwxyz + Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + Line 4 Abcdefghijklmnopqrstuvwxyz + Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + Line 6 Abcdefghijklmnopqrstuvwxyz + Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + Line 8 Abcdefghijklmnopqrstuvwxyz + Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + Line 10 Abcdefghijklmnopqrstuvwxyz + end of testfiLe]]) + end) + + end + + it('FileAppendPre, FileAppendPost', function() + execute('au BufNewFile *.c read Xtest.c') + -- Will load Xtest.c. + execute('e! foo.c') + execute("au FileAppendPre *.out '[,']s/new/NEW/") + execute('au FileAppendPost *.out !cat Xtest.c >>test.out') + -- Append it to the output file. + execute('w>>test.out') + -- Discard all prompts and messages. + feed('<C-L>') + -- Expect the decompressed file in the buffer. + execute('e test.out') + expect([[ + + /* + * Here is a NEW .c file + */]]) + end) + + it('FilterReadPre, FilterReadPost', function() + -- Write a special input file for this test block. + write_file('test.out', dedent([[ + startstart + ]]) .. text1 .. dedent([[ + + + start of test.c + /* + * Here is a new .c file + */ + end of test.c + ]]) .. text1 .. dedent([[ + + + /* + * Here is a NEW .c file + */ + /* + * Here is a new .c file + */ + ]]) .. text1 .. dedent([[ + + /* + * Here is a new .c file + */]])) + -- Need temp files here. + execute('set shelltemp') + execute('au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")') + execute('au FilterReadPre *.out exe "silent !sed s/e/E/ " . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))') + execute('au FilterReadPre *.out exe "silent !rm " . shellescape(expand("<afile>")) . ".t"') + execute("au FilterReadPost *.out '[,']s/x/X/g") + -- Edit the output file. + execute('e! test.out') + execute('23,$!cat') + -- Discard all prompts and messages. + feed('<C-L>') + -- Remove CR for when sed adds them. + execute([[23,$s/\r$//]]) + expect([[ + startstart + start of testfile + line 2 Abcdefghijklmnopqrstuvwxyz + line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 4 Abcdefghijklmnopqrstuvwxyz + line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 6 Abcdefghijklmnopqrstuvwxyz + line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 8 Abcdefghijklmnopqrstuvwxyz + line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 10 Abcdefghijklmnopqrstuvwxyz + end of testfile + + start of test.c + /* + * Here is a new .c file + */ + end of test.c + start of testfile + line 2 Abcdefghijklmnopqrstuvwxyz + line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + line 4 Abcdefghijklmnopqrstuvwxyz + linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 6 AbcdefghijklmnopqrstuvwXyz + linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 8 AbcdefghijklmnopqrstuvwXyz + linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 10 AbcdefghijklmnopqrstuvwXyz + End of testfile + + /* + * HEre is a NEW .c file + */ + /* + * HEre is a new .c file + */ + start of tEstfile + linE 2 AbcdefghijklmnopqrstuvwXyz + linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 4 AbcdefghijklmnopqrstuvwXyz + linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 6 AbcdefghijklmnopqrstuvwXyz + linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 8 AbcdefghijklmnopqrstuvwXyz + linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + linE 10 AbcdefghijklmnopqrstuvwXyz + End of testfile + /* + * HEre is a new .c file + */]]) + end) +end) diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua new file mode 100644 index 0000000000..3c264423ff --- /dev/null +++ b/test/functional/legacy/036_regexp_character_classes_spec.lua @@ -0,0 +1,271 @@ +-- Test character classes in regexp using regexpengine 0, 1, 2. + +local helpers = require('test.functional.helpers') +local ffi = require('ffi') +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect +local source, write_file = helpers.source, helpers.write_file + +local function sixlines(text) + local result = '' + for _ = 1, 6 do + result = result .. text .. '\n' + end + return result +end + +local function diff(text, nodedent) + local tmpname = os.tmpname() + if ffi.os == 'OSX' and string.match(tmpname, '^/tmp') then + tmpname = '/private'..tmpname + end + execute('w! '..tmpname) + helpers.wait() + local data = io.open(tmpname):read('*all') + if nodedent then + helpers.eq(text, data) + else + helpers.eq(helpers.dedent(text), data) + end + os.remove(tmpname) +end + +describe('character classes in regexp', function() + local ctrl1 = '\t\x0c\r' + local punct1 = " !\"#$%&'()#+'-./" + local digits = '0123456789' + local punct2 = ':;<=>?@' + local upper = 'ABCDEFGHIXYZ' + local punct3 = '[\\]^_`' + local lower = 'abcdefghiwxyz' + local punct4 = '{|}~' + local ctrl2 = '\x7f\x80\x82\x90\x9b' + local iso_text = '\xa6\xb1\xbc\xc7\xd3\xe9' -- "¦±¼ÇÓé" in utf-8 + setup(function() + -- The original test32.in file was not in utf-8 encoding and did also + -- contain some control characters. We use lua escape sequences to write + -- them to the test file. + local line = ctrl1..punct1..digits..punct2..upper..punct3..lower..punct4..ctrl2..iso_text + write_file('test36.in', sixlines(line)) + end) + before_each(function() + clear() + execute('e test36.in') + end) + teardown(function() + os.remove('test36.in') + end) + + it('is working', function() + source([[ + 1 s/\%#=0\d//g + 2 s/\%#=1\d//g + 3 s/\%#=2\d//g + 4 s/\%#=0[0-9]//g + 5 s/\%#=1[0-9]//g + 6 s/\%#=2[0-9]//g]]) + diff(sixlines(ctrl1..punct1..punct2..upper..punct3..lower..punct4.. + ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\D//g + 2 s/\%#=1\D//g + 3 s/\%#=2\D//g + 4 s/\%#=0[^0-9]//g + 5 s/\%#=1[^0-9]//g + 6 s/\%#=2[^0-9]//g]]) + expect([[ + 0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\o//g + 2 s/\%#=1\o//g + 3 s/\%#=2\o//g + 4 s/\%#=0[0-7]//g + 5 s/\%#=1[0-7]//g + 6 s/\%#=2[0-7]//g]]) + diff(sixlines(ctrl1..punct1..'89'..punct2..upper..punct3..lower..punct4..ctrl2.. + iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\O//g + 2 s/\%#=1\O//g + 3 s/\%#=2\O//g + 4 s/\%#=0[^0-7]//g + 5 s/\%#=1[^0-7]//g + 6 s/\%#=2[^0-7]//g]]) + expect([[ + 01234567 + 01234567 + 01234567 + 01234567 + 01234567 + 01234567]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\x//g + 2 s/\%#=1\x//g + 3 s/\%#=2\x//g + 4 s/\%#=0[0-9A-Fa-f]//g + 5 s/\%#=1[0-9A-Fa-f]//g + 6 s/\%#=2[0-9A-Fa-f]//g]]) + diff(sixlines(ctrl1..punct1..punct2..'GHIXYZ'..punct3..'ghiwxyz'..punct4..ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\X//g + 2 s/\%#=1\X//g + 3 s/\%#=2\X//g + 4 s/\%#=0[^0-9A-Fa-f]//g + 5 s/\%#=1[^0-9A-Fa-f]//g + 6 s/\%#=2[^0-9A-Fa-f]//g]]) + expect([[ + 0123456789ABCDEFabcdef + 0123456789ABCDEFabcdef + 0123456789ABCDEFabcdef + 0123456789ABCDEFabcdef + 0123456789ABCDEFabcdef + 0123456789ABCDEFabcdef]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\w//g + 2 s/\%#=1\w//g + 3 s/\%#=2\w//g + 4 s/\%#=0[0-9A-Za-z_]//g + 5 s/\%#=1[0-9A-Za-z_]//g + 6 s/\%#=2[0-9A-Za-z_]//g]]) + diff(sixlines(ctrl1..punct1..punct2..'[\\]^`'..punct4..ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\W//g + 2 s/\%#=1\W//g + 3 s/\%#=2\W//g + 4 s/\%#=0[^0-9A-Za-z_]//g + 5 s/\%#=1[^0-9A-Za-z_]//g + 6 s/\%#=2[^0-9A-Za-z_]//g]]) + expect([[ + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz + 0123456789ABCDEFGHIXYZ_abcdefghiwxyz]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\h//g + 2 s/\%#=1\h//g + 3 s/\%#=2\h//g + 4 s/\%#=0[A-Za-z_]//g + 5 s/\%#=1[A-Za-z_]//g + 6 s/\%#=2[A-Za-z_]//g]]) + diff(sixlines(ctrl1..punct1..digits..punct2..'[\\]^`'..punct4..ctrl2.. + iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\H//g + 2 s/\%#=1\H//g + 3 s/\%#=2\H//g + 4 s/\%#=0[^A-Za-z_]//g + 5 s/\%#=1[^A-Za-z_]//g + 6 s/\%#=2[^A-Za-z_]//g]]) + expect([[ + ABCDEFGHIXYZ_abcdefghiwxyz + ABCDEFGHIXYZ_abcdefghiwxyz + ABCDEFGHIXYZ_abcdefghiwxyz + ABCDEFGHIXYZ_abcdefghiwxyz + ABCDEFGHIXYZ_abcdefghiwxyz + ABCDEFGHIXYZ_abcdefghiwxyz]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\a//g + 2 s/\%#=1\a//g + 3 s/\%#=2\a//g + 4 s/\%#=0[A-Za-z]//g + 5 s/\%#=1[A-Za-z]//g + 6 s/\%#=2[A-Za-z]//g]]) + diff(sixlines(ctrl1..punct1..digits..punct2..punct3..punct4..ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\A//g + 2 s/\%#=1\A//g + 3 s/\%#=2\A//g + 4 s/\%#=0[^A-Za-z]//g + 5 s/\%#=1[^A-Za-z]//g + 6 s/\%#=2[^A-Za-z]//g]]) + expect([[ + ABCDEFGHIXYZabcdefghiwxyz + ABCDEFGHIXYZabcdefghiwxyz + ABCDEFGHIXYZabcdefghiwxyz + ABCDEFGHIXYZabcdefghiwxyz + ABCDEFGHIXYZabcdefghiwxyz + ABCDEFGHIXYZabcdefghiwxyz]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\l//g + 2 s/\%#=1\l//g + 3 s/\%#=2\l//g + 4 s/\%#=0[a-z]//g + 5 s/\%#=1[a-z]//g + 6 s/\%#=2[a-z]//g]]) + diff(sixlines(ctrl1..punct1..digits..punct2..upper..punct3..punct4.. + ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\L//g + 2 s/\%#=1\L//g + 3 s/\%#=2\L//g + 4 s/\%#=0[^a-z]//g + 5 s/\%#=1[^a-z]//g + 6 s/\%#=2[^a-z]//g]]) + expect([[ + abcdefghiwxyz + abcdefghiwxyz + abcdefghiwxyz + abcdefghiwxyz + abcdefghiwxyz + abcdefghiwxyz]]) + end) + it('is working', function() + source([[ + 1 s/\%#=0\u//g + 2 s/\%#=1\u//g + 3 s/\%#=2\u//g + 4 s/\%#=0[A-Z]//g + 5 s/\%#=1[A-Z]//g + 6 s/\%#=2[A-Z]//g]]) + diff(sixlines(ctrl1..punct1..digits..punct2..punct3..lower..punct4.. + ctrl2..iso_text)) + end) + it('is working', function() + source([[ + 1 s/\%#=0\U//g + 2 s/\%#=1\U//g + 3 s/\%#=2\U//g + 4 s/\%#=0[^A-Z]//g + 5 s/\%#=1[^A-Z]//g + 6 s/\%#=2[^A-Z]//g]]) + expect([[ + ABCDEFGHIXYZ + ABCDEFGHIXYZ + ABCDEFGHIXYZ + ABCDEFGHIXYZ + ABCDEFGHIXYZ + ABCDEFGHIXYZ]]) + end) +end) diff --git a/test/functional/legacy/062_tab_pages_spec.lua b/test/functional/legacy/062_tab_pages_spec.lua index f1c8b8d58b..c3cdcac471 100644 --- a/test/functional/legacy/062_tab_pages_spec.lua +++ b/test/functional/legacy/062_tab_pages_spec.lua @@ -139,6 +139,7 @@ describe('tab pages', function() autocmd TabLeave * :call add(g:r, 'TabLeave') autocmd WinLeave * :call add(g:r, 'WinLeave') autocmd BufLeave * :call add(g:r, 'BufLeave') + autocmd TabNew * :call add(g:r, 'TabNew') let t:a='a' C tab split let t:a='b' @@ -185,11 +186,13 @@ describe('tab pages', function() === tab split === WinLeave TabLeave + TabNew WinEnter TabEnter === tabnew === WinLeave TabLeave + TabNew WinEnter TabEnter BufLeave @@ -222,6 +225,7 @@ describe('tab pages', function() === tabnew === WinLeave TabLeave + TabNew WinEnter TabEnter BufLeave diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua index 855e9c6271..6349371808 100644 --- a/test/functional/legacy/autocmd_option_spec.lua +++ b/test/functional/legacy/autocmd_option_spec.lua @@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers') local nvim = helpers.meths local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq local curbuf, buf = helpers.curbuf, helpers.bufmeths +local curwin = helpers.curwin +local redir_exec = helpers.redir_exec local source, execute = helpers.source, helpers.execute local function declare_hook_function() @@ -86,7 +88,7 @@ end local function make_buffer() local old_buf = curbuf() - execute('new') + execute('botright new') local new_buf = curbuf() execute('wincmd p') -- move previous window @@ -96,6 +98,19 @@ local function make_buffer() return new_buf end +local function get_new_window_number() + local old_win = curwin() + execute('botright new') + local new_win = curwin() + local new_winnr = redir_exec('echo winnr()') + execute('wincmd p') -- move previous window + + neq(old_win, new_win) + eq(old_win, curwin()) + + return new_winnr:gsub('\n', '') +end + describe('au OptionSet', function() describe('with any opton (*)', function() @@ -248,6 +263,32 @@ describe('au OptionSet', function() end) end) + describe('being set by setwinvar()', function() + it('should not trigger because option name does not match with backup', function() + set_hook('backup') + + execute('call setwinvar(1, "&l:bk", 1)') + expected_empty() + end) + + it('should trigger, use correct option name backup', function() + set_hook('backup') + + execute('call setwinvar(1, "&backup", 1)') + expected_combination({'backup', 0, 1, 'local'}) + end) + + it('should not trigger if the current window is different from the targetted window', function() + set_hook('cursorcolumn') + + local new_winnr = get_new_window_number() + + execute('call setwinvar(' .. new_winnr .. ', "&cursorcolumn", 1)') + -- expected_combination({'cursorcolumn', 0, 1, 'local', {winnr = new_winnr}}) + expected_empty() + end) + end) + describe('being set by neovim api', function() it('should trigger if a boolean option be set globally', function() set_hook('autochdir') diff --git a/test/functional/legacy/charsearch_spec.lua b/test/functional/legacy/charsearch_spec.lua new file mode 100644 index 0000000000..4a83801cfc --- /dev/null +++ b/test/functional/legacy/charsearch_spec.lua @@ -0,0 +1,42 @@ +-- Test for character searches + +local helpers = require('test.functional.helpers') +local feed, insert = helpers.feed, helpers.insert +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('charsearch', function() + setup(clear) + + it('is working', function() + insert([[ + Xabcdefghijkemnopqretuvwxyz + Yabcdefghijkemnopqretuvwxyz + Zabcdefghijkemnokqretkvwxyz]]) + + -- Check that "fe" and ";" work. + execute('/^X') + feed('ylfep;;p,,p') + -- Check that save/restore works. + execute('/^Y') + feed('ylfep') + execute('let csave = getcharsearch()') + feed('fip') + execute('call setcharsearch(csave)') + feed(';p;p') + -- Check that setcharsearch() changes the settings. + execute('/^Z') + feed('ylfep') + execute("call setcharsearch({'char': 'k'})") + feed(';p') + execute("call setcharsearch({'forward': 0})") + feed('$;p') + execute("call setcharsearch({'until': 1})") + feed(';;p') + + -- Assert buffer contents. + expect([[ + XabcdeXfghijkeXmnopqreXtuvwxyz + YabcdeYfghiYjkeYmnopqreYtuvwxyz + ZabcdeZfghijkZZemnokqretkZvwxyz]]) + end) +end) diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua index c16b1c45f4..d33ba6b5fd 100644 --- a/test/functional/legacy/utf8_spec.lua +++ b/test/functional/legacy/utf8_spec.lua @@ -4,9 +4,10 @@ local helpers = require('test.functional.helpers') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect local eq, eval = helpers.eq, helpers.eval +local source = helpers.source describe('utf8', function() - setup(clear) + before_each(clear) it('is working', function() insert('start:') @@ -50,4 +51,33 @@ describe('utf8', function() eq(1, eval('strchars("\\u20dd", 0)')) eq(1, eval('strchars("\\u20dd", 1)')) end) + + it('customlist completion', function() + source([[ + function! CustomComplete1(lead, line, pos) + return ['あ', 'い'] + endfunction + command -nargs=1 -complete=customlist,CustomComplete1 Test1 echo]]) + feed(":Test1 <C-L>'<C-B>$put='<CR>") + + source([[ + function! CustomComplete2(lead, line, pos) + return ['あたし', 'あたま', 'あたりめ'] + endfunction + command -nargs=1 -complete=customlist,CustomComplete2 Test2 echo]]) + feed(":Test2 <C-L>'<C-B>$put='<CR>") + + source([[ + function! CustomComplete3(lead, line, pos) + return ['Nこ', 'Nん', 'Nぶ'] + endfunction + command -nargs=1 -complete=customlist,CustomComplete3 Test3 echo]]) + feed(":Test3 <C-L>'<C-B>$put='<CR>") + + expect([[ + + Test1 + Test2 あた + Test3 N]]) + end) end) diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua new file mode 100644 index 0000000000..6da1521121 --- /dev/null +++ b/test/functional/terminal/edit_spec.lua @@ -0,0 +1,75 @@ +local helpers = require('test.functional.helpers') +local screen = require('test.functional.ui.screen') + +local curbufmeths = helpers.curbufmeths +local curwinmeths = helpers.curwinmeths +local nvim_dir = helpers.nvim_dir +local command = helpers.command +local meths = helpers.meths +local clear = helpers.clear +local eq = helpers.eq + +describe(':edit term://*', function() + local get_screen = function(columns, lines) + local scr = screen.new(columns, lines) + scr:attach(false) + return scr + end + + before_each(function() + clear() + meths.set_option('shell', nvim_dir .. '/shell-test') + meths.set_option('shellcmdflag', 'EXE') + end) + + it('runs TermOpen event', function() + meths.set_var('termopen_runs', {}) + command('autocmd TermOpen * :call add(g:termopen_runs, expand("<amatch>"))') + command('edit term://') + local termopen_runs = meths.get_var('termopen_runs') + eq(1, #termopen_runs) + eq(termopen_runs[1], termopen_runs[1]:match('^term://.//%d+:$')) + end) + + it('runs TermOpen early enough to respect terminal_scrollback_buffer_size', function() + local columns, lines = 20, 4 + local scr = get_screen(columns, lines) + local rep = 'a' + meths.set_option('shellcmdflag', 'REP ' .. rep) + local rep_size = rep:byte() + local sb = 10 + local gsb = 20 + meths.set_var('terminal_scrollback_buffer_size', gsb) + command('autocmd TermOpen * :let b:terminal_scrollback_buffer_size = ' + .. tostring(sb)) + command('edit term://foobar') + local bufcontents = {} + local winheight = curwinmeths.get_height() + -- I have no idea why there is + 4 needed. But otherwise it works fine with + -- different scrollbacks. + local shift = -4 + local buf_cont_start = rep_size - 1 - sb - winheight - shift + local bufline = function(i) return ('%d: foobar'):format(i) end + for i = buf_cont_start,(rep_size - 1) do + bufcontents[#bufcontents + 1] = bufline(i) + end + bufcontents[#bufcontents + 1] = '' + bufcontents[#bufcontents + 1] = '[Process exited 0]' + -- Do not ask me why displayed screen is one line *before* buffer + -- contents: buffer starts with 87:, screen with 86:. + local exp_screen = '\n' + local did_cursor = false + for i = 0,(winheight - 1) do + local line = bufline(buf_cont_start + i - 1) + exp_screen = (exp_screen + .. (did_cursor and '' or '^') + .. line + .. (' '):rep(columns - #line) + .. '|\n') + did_cursor = true + end + exp_screen = exp_screen .. (' '):rep(columns) .. '|\n' + scr:expect(exp_screen) + eq(bufcontents, curbufmeths.get_line_slice(1, -1, true, true)) + end) +end) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua new file mode 100644 index 0000000000..58f5b11de0 --- /dev/null +++ b/test/functional/ui/bufhl_spec.lua @@ -0,0 +1,261 @@ +local helpers = require('test.functional.helpers') +local Screen = require('test.functional.ui.screen') +local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert +local execute, request, neq = helpers.execute, helpers.request, helpers.neq + + +describe('Buffer highlighting', function() + local screen + local curbuf + + local hl_colors = { + NonText = Screen.colors.Blue, + Question = Screen.colors.SeaGreen, + String = Screen.colors.Fuchsia, + Statement = Screen.colors.Brown, + Special = Screen.colors.SlateBlue, + Identifier = Screen.colors.DarkCyan + } + + before_each(function() + clear() + execute("syntax on") + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ignore( {{bold=true, foreground=hl_colors.NonText}} ) + screen:set_default_attr_ids({ + [1] = {foreground = hl_colors.String}, + [2] = {foreground = hl_colors.Statement, bold = true}, + [3] = {foreground = hl_colors.Special}, + [4] = {bold = true, foreground = hl_colors.Special}, + [5] = {foreground = hl_colors.Identifier}, + [6] = {bold = true}, + [7] = {underline = true, bold = true, foreground = hl_colors.Special}, + [8] = {foreground = hl_colors.Special, underline = true} + }) + curbuf = request('vim_get_current_buffer') + end) + + after_each(function() + screen:detach() + end) + + local function add_hl(...) + return request('buffer_add_highlight', curbuf, ...) + end + + local function clear_hl(...) + return request('buffer_clear_highlight', curbuf, ...) + end + + + it('works', function() + insert([[ + these are some lines + with colorful text]]) + feed('+') + + screen:expect([[ + these are some lines | + with colorful tex^t | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + + add_hl(-1, "String", 0 , 10, 14) + add_hl(-1, "Statement", 1 , 5, -1) + + screen:expect([[ + these are {1:some} lines | + with {2:colorful tex^t} | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + + feed("ggo<esc>") + screen:expect([[ + these are {1:some} lines | + ^ | + with {2:colorful text} | + ~ | + ~ | + ~ | + ~ | + | + ]]) + + clear_hl(-1, 0 , -1) + screen:expect([[ + these are some lines | + ^ | + with colorful text | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + + describe('support adding multiple sources', function() + local id1, id2 + before_each(function() + insert([[ + a longer example + in order to demonstrate + combining highlights + from different sources]]) + + execute("hi ImportantWord gui=bold cterm=bold") + id1 = add_hl(0, "ImportantWord", 0, 2, 8) + add_hl(id1, "ImportantWord", 1, 12, -1) + add_hl(id1, "ImportantWord", 2, 0, 9) + add_hl(id1, "ImportantWord", 3, 5, 14) + + id2 = add_hl(0, "Special", 0, 2, 8) + add_hl(id2, "Identifier", 1, 3, 8) + add_hl(id2, "Special", 1, 14, 20) + add_hl(id2, "Underlined", 2, 6, 12) + add_hl(id2, "Underlined", 3, 0, 9) + neq(id1, id2) + + screen:expect([[ + a {4:longer} example | + in {5:order} to {6:de}{4:monstr}{6:ate} | + {6:combin}{7:ing}{8: hi}ghlights | + {8:from }{7:diff}{6:erent} source^s | + ~ | + ~ | + ~ | + :hi ImportantWord gui=bold cterm=bold | + ]]) + end) + + it('and clearing the first added', function() + clear_hl(id1, 0, -1) + screen:expect([[ + a {3:longer} example | + in {5:order} to de{3:monstr}ate | + combin{8:ing hi}ghlights | + {8:from diff}erent source^s | + ~ | + ~ | + ~ | + :hi ImportantWord gui=bold cterm=bold | + ]]) + end) + + it('and clearing the second added', function() + clear_hl(id2, 0, -1) + screen:expect([[ + a {6:longer} example | + in order to {6:demonstrate} | + {6:combining} highlights | + from {6:different} source^s | + ~ | + ~ | + ~ | + :hi ImportantWord gui=bold cterm=bold | + ]]) + end) + + it('and clearing line ranges', function() + clear_hl(-1, 0, 1) + clear_hl(id1, 1, 2) + clear_hl(id2, 2, -1) + screen:expect([[ + a longer example | + in {5:order} to de{3:monstr}ate | + {6:combining} highlights | + from {6:different} source^s | + ~ | + ~ | + ~ | + :hi ImportantWord gui=bold cterm=bold | + ]]) + end) + + it('and renumbering lines', function() + feed('3Gddggo<esc>') + screen:expect([[ + a {4:longer} example | + ^ | + in {5:order} to {6:de}{4:monstr}{6:ate} | + {8:from }{7:diff}{6:erent} sources | + ~ | + ~ | + ~ | + | + ]]) + + execute(':3move 4') + screen:expect([[ + a {4:longer} example | + | + {8:from }{7:diff}{6:erent} sources | + ^in {5:order} to {6:de}{4:monstr}{6:ate} | + ~ | + ~ | + ~ | + ::3move 4 | + ]]) + end) + end) + + it('prioritizes latest added highlight', function() + insert([[ + three overlapping colors]]) + add_hl(0, "Identifier", 0, 6, 17) + add_hl(0, "String", 0, 14, 23) + local id = add_hl(0, "Special", 0, 0, 9) + + screen:expect([[ + {3:three ove}{5:rlapp}{1:ing color}^s | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + + clear_hl(id, 0, 1) + screen:expect([[ + three {5:overlapp}{1:ing color}^s | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + + it('works with multibyte text', function() + insert([[ + Ta båten över sjön!]]) + add_hl(-1, "Identifier", 0, 3, 9) + add_hl(-1, "String", 0, 16, 21) + + screen:expect([[ + Ta {5:båten} över {1:sjön}^! | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) +end) diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index 4818830940..6f5cadaf81 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -25,6 +25,9 @@ describe('mappings', function() add_mapping('<s-up>', '<s-up>') add_mapping('<c-s-up>', '<c-s-up>') add_mapping('<c-s-a-up>', '<c-s-a-up>') + add_mapping('<c-s-a-d-up>', '<c-s-a-d-up>') + add_mapping('<c-d-a>', '<c-d-a>') + add_mapping('<d-1>', '<d-1>') end) it('ok', function() @@ -37,6 +40,12 @@ describe('mappings', function() check_mapping('<s-a-c-up>', '<c-s-a-up>') check_mapping('<a-c-s-up>', '<c-s-a-up>') check_mapping('<a-s-c-up>', '<c-s-a-up>') + check_mapping('<c-s-a-d-up>', '<c-s-a-d-up>') + check_mapping('<s-a-d-c-up>', '<c-s-a-d-up>') + check_mapping('<d-s-a-c-up>', '<c-s-a-d-up>') + check_mapping('<c-d-a>', '<c-d-a>') + check_mapping('<d-c-a>', '<c-d-a>') + check_mapping('<d-1>', '<d-1>') end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 80f46326ee..b35e0cde69 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -219,12 +219,23 @@ function Screen:expect(expected, attr_ids, attr_ignore) local ids = attr_ids or self._default_attr_ids local ignore = attr_ignore or self._default_attr_ignore self:wait(function() + local actual_rows = {} for i = 1, self._height do - local expected_row = expected_rows[i] - local actual_row = self:_row_repr(self._rows[i], ids, ignore) - if expected_row ~= actual_row then - return 'Row '..tostring(i)..' didn\'t match.\nExpected: "'.. - expected_row..'"\nActual: "'..actual_row..'"' + actual_rows[i] = self:_row_repr(self._rows[i], ids, ignore) + end + for i = 1, self._height do + if expected_rows[i] ~= actual_rows[i] then + local msg_expected_rows = {} + for j = 1, #expected_rows do + msg_expected_rows[j] = expected_rows[j] + end + msg_expected_rows[i] = '*' .. msg_expected_rows[i] + actual_rows[i] = '*' .. actual_rows[i] + return ( + 'Row ' .. tostring(i) .. ' didn\'t match.\n' + .. 'Expected:\n|' .. table.concat(msg_expected_rows, '|\n|') .. '|\n' + .. 'Actual:\n|' .. table.concat(actual_rows, '|\n|') .. '|' + ) end end end) diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua new file mode 100644 index 0000000000..78e25297f2 --- /dev/null +++ b/test/functional/viml/errorlist_spec.lua @@ -0,0 +1,49 @@ +local helpers = require('test.functional.helpers') + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local get_cur_win_var = helpers.curwinmeths.get_var +-- local exc_exec = helpers.exc_exec + +describe('setqflist()', function() + local setqflist = helpers.funcs.setqflist + + before_each(clear) + + it('sets w:quickfix_title', function() + setqflist({''}, 'r', 'foo') + command('copen') + eq(':foo', get_cur_win_var('quickfix_title')) + end) + + it('expects a proper type for {title}', function() + command('copen') + setqflist({''}, 'r', '5') + eq(':5', get_cur_win_var('quickfix_title')) + setqflist({''}, 'r', 6) + eq(':setqflist()', get_cur_win_var('quickfix_title')) + -- local exc = exc_exec('call setqflist([""], "r", function("function"))') + -- eq('Vim(call):E729: using Funcref as a String', exc) + -- exc = exc_exec('call setqflist([""], "r", [])') + -- eq('Vim(call):E730: using List as a String', exc) + -- exc = exc_exec('call setqflist([""], "r", {})') + -- eq('Vim(call):E731: using Dictionary as a String', exc) + end) +end) + +describe('setloclist()', function() + local setloclist = helpers.funcs.setloclist + + before_each(clear) + + it('sets w:quickfix_title for the correct window', function() + command('rightbelow vsplit') + setloclist(1, {''}, 'r', 'foo') + setloclist(2, {''}, 'r', 'bar') + command('lopen') + eq(':bar', get_cur_win_var('quickfix_title')) + command('lclose | wincmd w | lopen') + eq(':foo', get_cur_win_var('quickfix_title')) + end) +end) diff --git a/test/functional/viml/function_spec.lua b/test/functional/viml/function_spec.lua new file mode 100644 index 0000000000..665f5d4467 --- /dev/null +++ b/test/functional/viml/function_spec.lua @@ -0,0 +1,29 @@ +local helpers = require('test.functional.helpers') + +local clear = helpers.clear +local eq = helpers.eq +local exc_exec = helpers.exc_exec + +describe('Up to MAX_FUNC_ARGS arguments are handled by', function() + local max_func_args = 20 -- from eval.h + local range = helpers.funcs.range + + before_each(clear) + + it('printf()', function() + local printf = helpers.funcs.printf + local rep = helpers.funcs['repeat'] + local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,' + eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args)))) + local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)') + eq('Vim(call):E740: Too many arguments for function printf', ret) + end) + + it('rpcnotify()', function() + local rpcnotify = helpers.funcs.rpcnotify + local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args))) + eq(1, ret) + ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)') + eq('Vim(call):E740: Too many arguments for function rpcnotify', ret) + end) +end) |