aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/testdir/test_normal.vim
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-11-07 13:37:22 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-11-07 14:25:32 +0800
commitc00d241981f292a6529242bb98ed16cfc8c53ae4 (patch)
treea03acfc293cc5bfc0d78c4d8c6a0b847d37e95d7 /src/nvim/testdir/test_normal.vim
parent8f9ae5278464205004c421e49dad640808b2256f (diff)
downloadrneovim-c00d241981f292a6529242bb98ed16cfc8c53ae4.tar.gz
rneovim-c00d241981f292a6529242bb98ed16cfc8c53ae4.tar.bz2
rneovim-c00d241981f292a6529242bb98ed16cfc8c53ae4.zip
vim-patch:8.2.3788: lambda for option that is a function may be freed
Problem: Lambda for option that is a function may be garbage collected. Solution: Set a reference in the funcref. (Yegappan Lakshmanan, closes vim/vim#9330) https://github.com/vim/vim/commit/6ae8fae8696623b527c7fb22567f6a3705b2f0dd Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src/nvim/testdir/test_normal.vim')
-rw-r--r--src/nvim/testdir/test_normal.vim249
1 files changed, 120 insertions, 129 deletions
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index b9cc858cdb..b3e0be8f77 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -3,6 +3,7 @@
source shared.vim
source check.vim
source view_util.vim
+source vim9.vim
source screendump.vim
func Setup_NewWindow()
@@ -463,110 +464,122 @@ func Test_opfunc_callback()
let g:OpFuncArgs = [a:val, a:type]
endfunc
- " Test for using a function()
- set opfunc=function('MyopFunc',\ [11])
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([11, 'char'], g:OpFuncArgs)
-
- " Using a funcref variable to set 'operatorfunc'
- let Fn = function('MyopFunc', [12])
- let &opfunc = Fn
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([12, 'char'], g:OpFuncArgs)
-
- " Using a string(funcref_variable) to set 'operatorfunc'
- let Fn = function('MyopFunc', [13])
- let &operatorfunc = string(Fn)
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([13, 'char'], g:OpFuncArgs)
-
- " Test for using a funcref()
- set operatorfunc=funcref('MyopFunc',\ [14])
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([14, 'char'], g:OpFuncArgs)
-
- " Using a funcref variable to set 'operatorfunc'
- let Fn = funcref('MyopFunc', [15])
- let &opfunc = Fn
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([15, 'char'], g:OpFuncArgs)
-
- " Using a string(funcref_variable) to set 'operatorfunc'
- let Fn = funcref('MyopFunc', [16])
- let &opfunc = string(Fn)
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([16, 'char'], g:OpFuncArgs)
+ let lines =<< trim END
+ #" Test for using a function()
+ set opfunc=function('g:MyopFunc',\ [10])
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([10, 'char'], g:OpFuncArgs)
- " Test for using a lambda function using set
- set opfunc={a\ ->\ MyopFunc(17,\ a)}
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([17, 'char'], g:OpFuncArgs)
+ #" Using a funcref variable to set 'operatorfunc'
+ VAR Fn = function('g:MyopFunc', [11])
+ LET &opfunc = Fn
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([11, 'char'], g:OpFuncArgs)
- " Test for using a lambda function using let
- let &opfunc = {a -> MyopFunc(18, a)}
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([18, 'char'], g:OpFuncArgs)
+ #" Using a string(funcref_variable) to set 'operatorfunc'
+ LET Fn = function('g:MyopFunc', [12])
+ LET &operatorfunc = string(Fn)
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([12, 'char'], g:OpFuncArgs)
- " Set 'operatorfunc' to a string(lambda expression)
- let &opfunc = '{a -> MyopFunc(19, a)}'
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([19, 'char'], g:OpFuncArgs)
+ #" Test for using a funcref()
+ set operatorfunc=funcref('g:MyopFunc',\ [13])
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([13, 'char'], g:OpFuncArgs)
- " Set 'operatorfunc' to a variable with a lambda expression
- let Lambda = {a -> MyopFunc(20, a)}
- let &opfunc = Lambda
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([20, 'char'], g:OpFuncArgs)
+ #" Using a funcref variable to set 'operatorfunc'
+ LET Fn = funcref('g:MyopFunc', [14])
+ LET &opfunc = Fn
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([14, 'char'], g:OpFuncArgs)
- " Set 'operatorfunc' to a string(variable with a lambda expression)
- let Lambda = {a -> MyopFunc(21, a)}
- let &opfunc = string(Lambda)
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([21, 'char'], g:OpFuncArgs)
+ #" Using a string(funcref_variable) to set 'operatorfunc'
+ LET Fn = funcref('g:MyopFunc', [15])
+ LET &opfunc = string(Fn)
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([15, 'char'], g:OpFuncArgs)
- " Try to use 'operatorfunc' after the function is deleted
- func TmpOpFunc(type)
- let g:OpFuncArgs = [22, a:type]
- endfunc
- let &opfunc = function('TmpOpFunc')
- delfunc TmpOpFunc
- call test_garbagecollect_now()
- let g:OpFuncArgs = []
- call assert_fails('normal! g@l', 'E117:')
- call assert_equal([], g:OpFuncArgs)
+ #" Test for using a lambda function using set
+ VAR optval = "LSTART a LMIDDLE MyopFunc(16, a) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set opfunc=" .. optval
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([16, 'char'], g:OpFuncArgs)
- " Try to use a function with two arguments for 'operatorfunc'
- func! MyopFunc2(x, y)
- let g:OpFuncArgs = [a:x, a:y]
- endfunc
- set opfunc=MyopFunc2
- let g:OpFuncArgs = []
- call assert_fails('normal! g@l', 'E119:')
- call assert_equal([], g:OpFuncArgs)
+ #" Test for using a lambda function using LET
+ LET &opfunc = LSTART a LMIDDLE MyopFunc(17, a) LEND
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([17, 'char'], g:OpFuncArgs)
- " Try to use a lambda function with two arguments for 'operatorfunc'
- let &opfunc = {a, b -> MyopFunc(23, b)}
- let g:OpFuncArgs = []
- call assert_fails('normal! g@l', 'E119:')
- call assert_equal([], g:OpFuncArgs)
+ #" Set 'operatorfunc' to a string(lambda expression)
+ LET &opfunc = 'LSTART a LMIDDLE MyopFunc(18, a) LEND'
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([18, 'char'], g:OpFuncArgs)
- " Test for clearing the 'operatorfunc' option
- set opfunc=''
- set opfunc&
+ #" Set 'operatorfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a LMIDDLE MyopFunc(19, a) LEND
+ LET &opfunc = Lambda
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([19, 'char'], g:OpFuncArgs)
- call assert_fails("set opfunc=function('abc')", "E700:")
- call assert_fails("set opfunc=funcref('abc')", "E700:")
+ #" Set 'operatorfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a LMIDDLE MyopFunc(20, a) LEND
+ LET &opfunc = string(Lambda)
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([20, 'char'], g:OpFuncArgs)
+
+ #" Try to use 'operatorfunc' after the function is deleted
+ func g:TmpOpFunc(type)
+ LET g:OpFuncArgs = [21, a:type]
+ endfunc
+ LET &opfunc = function('g:TmpOpFunc')
+ delfunc g:TmpOpFunc
+ call test_garbagecollect_now()
+ LET g:OpFuncArgs = []
+ call assert_fails('normal! g@l', 'E117:')
+ call assert_equal([], g:OpFuncArgs)
+
+ #" Try to use a function with two arguments for 'operatorfunc'
+ func MyopFunc2(x, y)
+ LET g:OpFuncArgs = [a:x, a:y]
+ endfunc
+ set opfunc=MyopFunc2
+ LET g:OpFuncArgs = []
+ call assert_fails('normal! g@l', 'E119:')
+ call assert_equal([], g:OpFuncArgs)
+
+ #" Try to use a lambda function with two arguments for 'operatorfunc'
+ LET &opfunc = LSTART a, b LMIDDLE MyopFunc(22, b) LEND
+ LET g:OpFuncArgs = []
+ call assert_fails('normal! g@l', 'E119:')
+ call assert_equal([], g:OpFuncArgs)
+
+ #" Test for clearing the 'operatorfunc' option
+ set opfunc=''
+ set opfunc&
+ call assert_fails("set opfunc=function('abc')", "E700:")
+ call assert_fails("set opfunc=funcref('abc')", "E700:")
+
+ #" set 'operatorfunc' to a non-existing function
+ LET &opfunc = function('g:MyopFunc', [23])
+ call assert_fails("set opfunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &opfunc = function('NonExistingFunc')", 'E700:')
+ LET g:OpFuncArgs = []
+ normal! g@l
+ call assert_equal([23, 'char'], g:OpFuncArgs)
+ END
+ call CheckTransLegacySuccess(lines)
" Using Vim9 lambda expression in legacy context should fail
" set opfunc=(a)\ =>\ MyopFunc(24,\ a)
@@ -574,19 +587,24 @@ func Test_opfunc_callback()
" call assert_fails('normal! g@l', 'E117:')
call assert_equal([], g:OpFuncArgs)
- " set 'operatorfunc' to a non-existing function
- let &opfunc = function('MyopFunc', [25])
- call assert_fails("set opfunc=function('NonExistingFunc')", 'E700:')
- call assert_fails("let &opfunc = function('NonExistingFunc')", 'E700:')
- let g:OpFuncArgs = []
- normal! g@l
- call assert_equal([25, 'char'], g:OpFuncArgs)
+ " set 'operatorfunc' to a partial with dict. This used to cause a crash.
+ func SetOpFunc()
+ let operator = {'execute': function('OperatorExecute')}
+ let &opfunc = operator.execute
+ endfunc
+ func OperatorExecute(_) dict
+ endfunc
+ call SetOpFunc()
+ call test_garbagecollect_now()
+ set operatorfunc=
+ delfunc SetOpFunc
+ delfunc OperatorExecute
" Vim9 tests
let lines =<< trim END
vim9script
- # Test for using function()
+ # Test for using a def function with opfunc
def g:Vim9opFunc(val: number, type: string): void
g:OpFuncArgs = [val, type]
enddef
@@ -594,33 +612,6 @@ func Test_opfunc_callback()
g:OpFuncArgs = []
normal! g@l
assert_equal([60, 'char'], g:OpFuncArgs)
-
- # Test for using a lambda
- &opfunc = (a) => Vim9opFunc(61, a)
- g:OpFuncArgs = []
- normal! g@l
- assert_equal([61, 'char'], g:OpFuncArgs)
-
- # Test for using a string(lambda)
- &opfunc = '(a) => Vim9opFunc(62, a)'
- g:OpFuncArgs = []
- normal! g@l
- assert_equal([62, 'char'], g:OpFuncArgs)
-
- # Test for using a variable with a lambda expression
- var Fn: func = (a) => Vim9opFunc(63, a)
- &opfunc = Fn
- g:OpFuncArgs = []
- normal! g@l
- assert_equal([63, 'char'], g:OpFuncArgs)
-
- # Test for using a string(variable with a lambda expression)
- Fn = (a) => Vim9opFunc(64, a)
- &opfunc = string(Fn)
- g:OpFuncArgs = []
- normal! g@l
- assert_equal([64, 'char'], g:OpFuncArgs)
- bw!
END
" call CheckScriptSuccess(lines)