diff options
Diffstat (limited to 'src/nvim/testdir/test_substitute.vim')
-rw-r--r-- | src/nvim/testdir/test_substitute.vim | 483 |
1 files changed, 474 insertions, 9 deletions
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index 20b760ac15..f795d1c0cf 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -1,4 +1,6 @@ -" Tests for multi-line regexps with ":s". +" Tests for the substitute (:s) command + +source shared.vim func Test_multiline_subst() enew! @@ -51,10 +53,12 @@ func Test_substitute_variants() \ { 'cmd': ':s/t/r/cg', 'exp': 'Tesring srring', 'prompt': 'a' }, \ { 'cmd': ':s/t/r/ci', 'exp': 'resting string', 'prompt': 'y' }, \ { 'cmd': ':s/t/r/cI', 'exp': 'Tesring string', 'prompt': 'y' }, + \ { 'cmd': ':s/t/r/c', 'exp': 'Testing string', 'prompt': 'n' }, \ { 'cmd': ':s/t/r/cn', 'exp': ln }, \ { 'cmd': ':s/t/r/cp', 'exp': 'Tesring string', 'prompt': 'y' }, \ { 'cmd': ':s/t/r/cl', 'exp': 'Tesring string', 'prompt': 'y' }, \ { 'cmd': ':s/t/r/gc', 'exp': 'Tesring srring', 'prompt': 'a' }, + \ { 'cmd': ':s/i/I/gc', 'exp': 'TestIng string', 'prompt': 'l' }, \ { 'cmd': ':s/foo/bar/ge', 'exp': ln }, \ { 'cmd': ':s/t/r/g', 'exp': 'Tesring srring' }, \ { 'cmd': ':s/t/r/gi', 'exp': 'resring srring' }, @@ -86,6 +90,7 @@ func Test_substitute_variants() \ { 'cmd': ':s//r/rp', 'exp': 'Testr string' }, \ { 'cmd': ':s//r/rl', 'exp': 'Testr string' }, \ { 'cmd': ':s//r/r', 'exp': 'Testr string' }, + \ { 'cmd': ':s/i/I/gc', 'exp': 'Testing string', 'prompt': 'q' }, \] for var in variants @@ -105,7 +110,7 @@ func Test_substitute_variants() call assert_equal(var.exp, getline('.'), msg) endfor endfor -endfunction +endfunc " Test the l, p, # flags. func Test_substitute_flags_lp() @@ -137,7 +142,7 @@ func Test_substitute_repeat() " This caused an invalid memory access. split Xfile s/^/x - call feedkeys("gQsc\<CR>y", 'tx') + call feedkeys("Qsc\<CR>y", 'tx') bwipe! endfunc @@ -149,7 +154,6 @@ func Run_SubCmd_Tests(tests) for t in a:tests let start = line('.') + 1 let end = start + len(t[2]) - 1 - " TODO: why is there a one second delay the first time we get here? exe "normal o" . t[0] call cursor(start, 1) exe t[1] @@ -184,7 +188,8 @@ func Test_sub_cmd_1() \ ['sSs', 's/S/\c/', ['scs']], \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]], \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']], - \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']] + \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']], + \ ['\', 's/\\/\\\\/', ['\\']] \ ] call Run_SubCmd_Tests(tests) endfunc @@ -215,7 +220,8 @@ func Test_sub_cmd_2() \ ['sSs', 's/S/\c/', ['scs']], \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]], \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']], - \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']] + \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']], + \ ['\', 's/\\/\\\\/', ['\\']] \ ] call Run_SubCmd_Tests(tests) endfunc @@ -288,7 +294,7 @@ endfunc " Test for *:s%* on :substitute. func Test_sub_cmd_6() - throw "skipped: Nvim removed POSIX-related 'cpoptions' flags" + throw 'Skipped: Nvim does not support cpoptions flag "/"' set magic& set cpo+=/ @@ -384,6 +390,10 @@ func Test_substitute_join() call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$')) call assert_equal('\n', histget("search", -1)) + call setline(1, ['foo', 'bar', 'baz', 'qux']) + call execute('1,2s/\n//') + call assert_equal(['foobarbaz', 'qux'], getline(1, '$')) + bwipe! endfunc @@ -398,6 +408,11 @@ func Test_substitute_count() call assert_fails('s/foo/bar/0', 'E939:') + call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo']) + 2,4s/foo/bar/ 10 + call assert_equal(['foo foo', 'foo foo', 'foo foo', 'bar foo', 'bar foo'], + \ getline(1, '$')) + bwipe! endfunc @@ -416,6 +431,10 @@ func Test_substitute_flag_n() " No substitution should have been done. call assert_equal(lines, getline(1, '$')) + %delete _ + call setline(1, ['A', 'Bar', 'Baz']) + call assert_equal("\n1 match on 1 line", execute('s/\nB\@=//gn')) + bwipe! endfunc @@ -656,10 +675,11 @@ func Test_nocatch_sub_failure_handling() endfunc new call setline(1, ['1 aaa', '2 aaa', '3 aaa']) - %s/aaa/\=Foo()/g + " need silent! to avoid a delay when entering Insert mode + silent! %s/aaa/\=Foo()/g call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3)) - " Trow without try-catch causes abort after the first line. + " Throw without try-catch causes abort after the first line. " We cannot test this, since it would stop executing the test script. " try/catch does not result in any changes @@ -749,6 +769,80 @@ func Test_sub_beyond_end() bwipe! endfunc +" Test for repeating last substitution using :~ and :&r +func Test_repeat_last_sub() + new + call setline(1, ['blue green yellow orange white']) + s/blue/red/ + let @/ = 'yellow' + ~ + let @/ = 'white' + :&r + let @/ = 'green' + s//gray + call assert_equal('red gray red orange red', getline(1)) + close! +endfunc + +" Test for Vi compatible substitution: +" \/{string}/, \?{string}? and \&{string}& +func Test_sub_vi_compatibility() + new + call setline(1, ['blue green yellow orange blue']) + let @/ = 'orange' + s\/white/ + let @/ = 'blue' + s\?amber? + let @/ = 'white' + s\&green& + call assert_equal('amber green yellow white green', getline(1)) + close! +endfunc + +" Test for substitute with the new text longer than the original text +func Test_sub_expand_text() + new + call setline(1, 'abcabcabcabcabcabcabcabc') + s/b/\=repeat('B', 10)/g + call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1)) + close! +endfunc + +" Test for command failures when the last substitute pattern is not set. +func Test_sub_with_no_last_pat() + let lines =<< trim [SCRIPT] + call assert_fails('~', 'E33:') + call assert_fails('s//abc/g', 'E476:') + call assert_fails('s\/bar', 'E476:') + call assert_fails('s\&bar&', 'E476:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + + " Nvim does not support cpoptions flag "/"' + " let lines =<< trim [SCRIPT] + " set cpo+=/ + " call assert_fails('s/abc/%/', 'E33:') + " call writefile(v:errors, 'Xresult') + " qall! + " [SCRIPT] + " call writefile(lines, 'Xscript') + " if RunVim([], [], '--clean -S Xscript') + " call assert_equal([], readfile('Xresult')) + " endif + + call delete('Xscript') + call delete('Xresult') +endfunc + +func Test_substitute() + call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g')) +endfunc + func Test_submatch_list_concatenate() let pat = 'A\(.\)' let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])} @@ -764,4 +858,375 @@ func Test_substitute_skipped_range() bwipe! endfunc +" This was using "old_sub" after it was freed. +func Test_using_old_sub() + " set compatible maxfuncdepth=10 + set maxfuncdepth=10 + new + call setline(1, 'some text.') + func Repl() + ~ + s/ + endfunc + silent! s/\%')/\=Repl() + + delfunc Repl + bwipe! + set nocompatible +endfunc + +" This was switching windows in between computing the length and using it. +func Test_sub_change_window() + silent! lfile + sil! norm o0000000000000000000000000000000000000000000000000000 + func Repl() + lopen + endfunc + silent! s/\%')/\=Repl() + bwipe! + bwipe! + delfunc Repl +endfunc + +" This was undoign a change in between computing the length and using it. +func Do_Test_sub_undo_change() + new + norm o0000000000000000000000000000000000000000000000000000 + silent! s/\%')/\=Repl() + bwipe! +endfunc + +func Test_sub_undo_change() + func Repl() + silent! norm g- + endfunc + call Do_Test_sub_undo_change() + + func! Repl() + silent earlier + endfunc + call Do_Test_sub_undo_change() + + delfunc Repl +endfunc + +" This was opening a command line window from the expression +func Test_sub_open_cmdline_win() + " the error only happens in a very specific setup, run a new Vim instance to + " get a clean starting point. + let lines =<< trim [SCRIPT] + set vb t_vb= + norm o0000000000000000000000000000000000000000000000000000 + func Replace() + norm q/ + endfunc + s/\%')/\=Replace() + redir >Xresult + messages + redir END + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '-u NONE -S Xscript') + call assert_match('E565: Not allowed to change text or change window', + \ readfile('Xresult')->join('XX')) + endif + + call delete('Xscript') + call delete('Xresult') +endfunc + +" Test for the 2-letter and 3-letter :substitute commands +func Test_substitute_short_cmd() + new + call setline(1, ['one', 'one one one']) + s/one/two + call cursor(2, 1) + + " :sc + call feedkeys(":sc\<CR>y", 'xt') + call assert_equal('two one one', getline(2)) + + " :scg + call setline(2, 'one one one') + call feedkeys(":scg\<CR>nyq", 'xt') + call assert_equal('one two one', getline(2)) + + " :sci + call setline(2, 'ONE One onE') + call feedkeys(":sci\<CR>y", 'xt') + call assert_equal('two One onE', getline(2)) + + " :scI + set ignorecase + call setline(2, 'ONE One one') + call feedkeys(":scI\<CR>y", 'xt') + call assert_equal('ONE One two', getline(2)) + set ignorecase& + + " :scn + call setline(2, 'one one one') + let t = execute('scn')->split("\n") + call assert_equal(['1 match on 1 line'], t) + call assert_equal('one one one', getline(2)) + + " :scp + call setline(2, "\tone one one") + redir => output + call feedkeys(":scp\<CR>y", 'xt') + redir END + call assert_equal(' two one one', output->split("\n")[-1]) + call assert_equal("\ttwo one one", getline(2)) + + " :scl + call setline(2, "\tone one one") + redir => output + call feedkeys(":scl\<CR>y", 'xt') + redir END + call assert_equal("^Itwo one one$", output->split("\n")[-1]) + call assert_equal("\ttwo one one", getline(2)) + + " :sgc + call setline(2, 'one one one one one') + call feedkeys(":sgc\<CR>nyyq", 'xt') + call assert_equal('one two two one one', getline(2)) + + " :sg + call setline(2, 'one one one') + sg + call assert_equal('two two two', getline(2)) + + " :sgi + call setline(2, 'ONE One onE') + sgi + call assert_equal('two two two', getline(2)) + + " :sgI + set ignorecase + call setline(2, 'ONE One one') + sgI + call assert_equal('ONE One two', getline(2)) + set ignorecase& + + " :sgn + call setline(2, 'one one one') + let t = execute('sgn')->split("\n") + call assert_equal(['3 matches on 1 line'], t) + call assert_equal('one one one', getline(2)) + + " :sgp + call setline(2, "\tone one one") + redir => output + sgp + redir END + call assert_equal(' two two two', output->split("\n")[-1]) + call assert_equal("\ttwo two two", getline(2)) + + " :sgl + call setline(2, "\tone one one") + redir => output + sgl + redir END + call assert_equal("^Itwo two two$", output->split("\n")[-1]) + call assert_equal("\ttwo two two", getline(2)) + + " :sgr + call setline(2, "one one one") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + sgr + call assert_equal('xyz xyz xyz', getline(2)) + + " :sic + call cursor(1, 1) + s/one/two/e + call setline(2, "ONE One one") + call cursor(2, 1) + call feedkeys(":sic\<CR>y", 'xt') + call assert_equal('two One one', getline(2)) + + " :si + call setline(2, "ONE One one") + si + call assert_equal('two One one', getline(2)) + + " :siI + call setline(2, "ONE One one") + siI + call assert_equal('ONE One two', getline(2)) + + " :sin + call setline(2, 'ONE One onE') + let t = execute('sin')->split("\n") + call assert_equal(['1 match on 1 line'], t) + call assert_equal('ONE One onE', getline(2)) + + " :sip + call setline(2, "\tONE One onE") + redir => output + sip + redir END + call assert_equal(' two One onE', output->split("\n")[-1]) + call assert_equal("\ttwo One onE", getline(2)) + + " :sir + call setline(2, "ONE One onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + sir + call assert_equal('xyz One onE', getline(2)) + + " :sIc + call cursor(1, 1) + s/one/two/e + call setline(2, "ONE One one") + call cursor(2, 1) + call feedkeys(":sIc\<CR>y", 'xt') + call assert_equal('ONE One two', getline(2)) + + " :sIg + call setline(2, "ONE one onE one") + sIg + call assert_equal('ONE two onE two', getline(2)) + + " :sIi + call setline(2, "ONE One one") + sIi + call assert_equal('two One one', getline(2)) + + " :sI + call setline(2, "ONE One one") + sI + call assert_equal('ONE One two', getline(2)) + + " :sIn + call setline(2, 'ONE One one') + let t = execute('sIn')->split("\n") + call assert_equal(['1 match on 1 line'], t) + call assert_equal('ONE One one', getline(2)) + + " :sIp + call setline(2, "\tONE One one") + redir => output + sIp + redir END + call assert_equal(' ONE One two', output->split("\n")[-1]) + call assert_equal("\tONE One two", getline(2)) + + " :sIl + call setline(2, "\tONE onE one") + redir => output + sIl + redir END + call assert_equal("^IONE onE two$", output->split("\n")[-1]) + call assert_equal("\tONE onE two", getline(2)) + + " :sIr + call setline(2, "ONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + sIr + call assert_equal('ONE xyz onE', getline(2)) + + " :src + call setline(2, "ONE one one") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + call feedkeys(":src\<CR>y", 'xt') + call assert_equal('ONE xyz one', getline(2)) + + " :srg + call setline(2, "one one one") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + srg + call assert_equal('xyz xyz xyz', getline(2)) + + " :sri + call setline(2, "ONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + sri + call assert_equal('xyz one onE', getline(2)) + + " :srI + call setline(2, "ONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + srI + call assert_equal('ONE xyz onE', getline(2)) + + " :srn + call setline(2, "ONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + let t = execute('srn')->split("\n") + call assert_equal(['1 match on 1 line'], t) + call assert_equal('ONE one onE', getline(2)) + + " :srp + call setline(2, "\tONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + redir => output + srp + redir END + call assert_equal(' ONE xyz onE', output->split("\n")[-1]) + call assert_equal("\tONE xyz onE", getline(2)) + + " :srl + call setline(2, "\tONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + redir => output + srl + redir END + call assert_equal("^IONE xyz onE$", output->split("\n")[-1]) + call assert_equal("\tONE xyz onE", getline(2)) + + " :sr + call setline(2, "ONE one onE") + call cursor(2, 1) + s/abc/xyz/e + let @/ = 'one' + sr + call assert_equal('ONE xyz onE', getline(2)) + + " :sce + s/abc/xyz/e + call assert_fails("sc", 'E486:') + sce + " :sge + call assert_fails("sg", 'E486:') + sge + " :sie + call assert_fails("si", 'E486:') + sie + " :sIe + call assert_fails("sI", 'E486:') + sIe + + bw! +endfunc + +" This should be done last to reveal a memory leak when vim_regsub_both() is +" called to evaluate an expression but it is not used in a second call. +func Test_z_substitute_expr_leak() + func SubExpr() + ~n + endfunc + silent! s/\%')/\=SubExpr() + delfunc SubExpr +endfunc + " vim: shiftwidth=2 sts=2 expandtab |