summaryrefslogtreecommitdiffstats
path: root/src/testdir/test_normal.vim
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2021-12-12 16:26:44 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-12 16:26:44 +0000
commit6ae8fae8696623b527c7fb22567f6a3705b2f0dd (patch)
tree5013ad6590516571ae06f992906c4270d7f03b45 /src/testdir/test_normal.vim
parent6e371ecb27227ff8fedd8561d0f3880a17576848 (diff)
patch 8.2.3788: lambda for option that is a function may be freedv8.2.3788
Problem: Lambda for option that is a function may be garbage collected. Solution: Set a reference in the funcref. (Yegappan Lakshmanan, closes #9330)
Diffstat (limited to 'src/testdir/test_normal.vim')
-rw-r--r--src/testdir/test_normal.vim248
1 files changed, 119 insertions, 129 deletions
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index 3e0de6f06e..8383dde395 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -448,110 +448,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)
@@ -559,19 +571,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
@@ -579,33 +596,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)