1" Test binding arguments to a Funcref. 2 3" NOTE: This function may cause memory leaks to be reported. 4" That is because when fork/exec fails memory is not freed. Since the process 5" exists right away it's not a real leak. 6func Test_job_start_fails() 7 if has('job') 8 let job = job_start('axdfxsdf') 9 for i in range(100) 10 let status = job_status(job) 11 if status == 'dead' || status == 'fail' 12 break 13 endif 14 sleep 10m 15 endfor 16 if has('unix') 17 call assert_equal('dead', job_status(job)) 18 else 19 call assert_equal('fail', job_status(job)) 20 endif 21 unlet job 22 endif 23endfunc 24 25func MyFunc(arg1, arg2, arg3) 26 return a:arg1 . '/' . a:arg2 . '/' . a:arg3 27endfunc 28 29func MySort(up, one, two) 30 if a:one == a:two 31 return 0 32 endif 33 if a:up 34 return a:one > a:two ? 1 : -1 35 endif 36 return a:one < a:two ? 1 : -1 37endfunc 38 39func MyMap(sub, index, val) 40 return a:val - a:sub 41endfunc 42 43func MyFilter(threshold, index, val) 44 return a:val > a:threshold 45endfunc 46 47func Test_partial_args() 48 let Cb = function('MyFunc', ["foo", "bar"]) 49 50 call Cb("zzz") 51 call assert_equal("foo/bar/xxx", Cb("xxx")) 52 call assert_equal("foo/bar/yyy", call(Cb, ["yyy"])) 53 let Cb2 = function(Cb) 54 call assert_equal("foo/bar/zzz", Cb2("zzz")) 55 let Cb3 = function(Cb, ["www"]) 56 call assert_equal("foo/bar/www", Cb3()) 57 58 let Cb = function('MyFunc', []) 59 call assert_equal("a/b/c", Cb("a", "b", "c")) 60 let Cb2 = function(Cb, []) 61 call assert_equal("a/b/d", Cb2("a", "b", "d")) 62 let Cb3 = function(Cb, ["a", "b"]) 63 call assert_equal("a/b/e", Cb3("e")) 64 65 let Sort = function('MySort', [1]) 66 call assert_equal([1, 2, 3], sort([3, 1, 2], Sort)) 67 let Sort = function('MySort', [0]) 68 call assert_equal([3, 2, 1], sort([3, 1, 2], Sort)) 69 70 let Map = function('MyMap', [2]) 71 call assert_equal([-1, 0, 1], map([1, 2, 3], Map)) 72 let Map = function('MyMap', [3]) 73 call assert_equal([-2, -1, 0], map([1, 2, 3], Map)) 74 75 let Filter = function('MyFilter', [1]) 76 call assert_equal([2, 3], filter([1, 2, 3], Filter)) 77 let Filter = function('MyFilter', [2]) 78 call assert_equal([3], filter([1, 2, 3], Filter)) 79endfunc 80 81func MyDictFunc(arg1, arg2) dict 82 return self.name . '/' . a:arg1 . '/' . a:arg2 83endfunc 84 85func Test_partial_dict() 86 let dict = {'name': 'hello'} 87 let Cb = function('MyDictFunc', ["foo", "bar"], dict) 88 call assert_equal("hello/foo/bar", Cb()) 89 call assert_fails('Cb("xxx")', 'E492:') 90 91 let Cb = function('MyDictFunc', ["foo"], dict) 92 call assert_equal("hello/foo/xxx", Cb("xxx")) 93 call assert_fails('Cb()', 'E492:') 94 95 let Cb = function('MyDictFunc', [], dict) 96 call assert_equal("hello/ttt/xxx", Cb("ttt", "xxx")) 97 call assert_fails('Cb("yyy")', 'E492:') 98 99 let Cb = function('MyDictFunc', dict) 100 call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy")) 101 call assert_fails('Cb("fff")', 'E492:') 102 103 let Cb = function('MyDictFunc', dict) 104 call assert_equal({"foo": "hello/foo/1", "bar": "hello/bar/2"}, map({"foo": 1, "bar": 2}, Cb)) 105 106 let dict = {"tr": function('tr', ['hello', 'h', 'H'])} 107 call assert_equal("Hello", dict.tr()) 108endfunc 109 110func Test_partial_implicit() 111 let dict = {'name': 'foo'} 112 func dict.MyFunc(arg) dict 113 return self.name . '/' . a:arg 114 endfunc 115 116 call assert_equal('foo/bar', dict.MyFunc('bar')) 117 118 call assert_fails('let func = dict.MyFunc', 'E704:') 119 let Func = dict.MyFunc 120 call assert_equal('foo/aaa', Func('aaa')) 121 122 let Func = function(dict.MyFunc, ['bbb']) 123 call assert_equal('foo/bbb', Func()) 124endfunc 125 126fun InnerCall(funcref) 127 return a:funcref 128endfu 129 130fun OuterCall() 131 let opt = { 'func' : function('sin') } 132 call InnerCall(opt.func) 133endfu 134 135func Test_function_in_dict() 136 call OuterCall() 137endfunc 138 139function! s:cache_clear() dict 140 return self.name 141endfunction 142 143func Test_script_function_in_dict() 144 let s:obj = {'name': 'foo'} 145 let s:obj2 = {'name': 'bar'} 146 147 let s:obj['clear'] = function('s:cache_clear') 148 149 call assert_equal('foo', s:obj.clear()) 150 let F = s:obj.clear 151 call assert_equal('foo', F()) 152 call assert_equal('foo', call(s:obj.clear, [], s:obj)) 153 call assert_equal('bar', call(s:obj.clear, [], s:obj2)) 154 155 let s:obj2['clear'] = function('s:cache_clear') 156 call assert_equal('bar', s:obj2.clear()) 157 let B = s:obj2.clear 158 call assert_equal('bar', B()) 159endfunc 160 161function! s:cache_arg(arg) dict 162 let s:result = self.name . '/' . a:arg 163 return s:result 164endfunction 165 166func Test_script_function_in_dict_arg() 167 let s:obj = {'name': 'foo'} 168 let s:obj['clear'] = function('s:cache_arg') 169 170 call assert_equal('foo/bar', s:obj.clear('bar')) 171 let F = s:obj.clear 172 let s:result = '' 173 call assert_equal('foo/bar', F('bar')) 174 call assert_equal('foo/bar', s:result) 175 176 let s:obj['clear'] = function('s:cache_arg', ['bar']) 177 call assert_equal('foo/bar', s:obj.clear()) 178 let s:result = '' 179 call s:obj.clear() 180 call assert_equal('foo/bar', s:result) 181 182 let F = s:obj.clear 183 call assert_equal('foo/bar', F()) 184 let s:result = '' 185 call F() 186 call assert_equal('foo/bar', s:result) 187 188 call assert_equal('foo/bar', call(s:obj.clear, [], s:obj)) 189endfunc 190 191func Test_partial_exists() 192 let F = function('MyFunc') 193 call assert_true(exists('*F')) 194 let lF = [F] 195 call assert_true(exists('*lF[0]')) 196 197 let F = function('MyFunc', ['arg']) 198 call assert_true(exists('*F')) 199 let lF = [F] 200 call assert_true(exists('*lF[0]')) 201endfunc 202 203func Test_partial_string() 204 let F = function('MyFunc') 205 call assert_equal("function('MyFunc')", string(F)) 206 let F = function('MyFunc', ['foo']) 207 call assert_equal("function('MyFunc', ['foo'])", string(F)) 208 let F = function('MyFunc', ['foo', 'bar']) 209 call assert_equal("function('MyFunc', ['foo', 'bar'])", string(F)) 210 let d = {'one': 1} 211 let F = function('MyFunc', d) 212 call assert_equal("function('MyFunc', {'one': 1})", string(F)) 213 let F = function('MyFunc', ['foo'], d) 214 call assert_equal("function('MyFunc', ['foo'], {'one': 1})", string(F)) 215endfunc 216 217func Test_func_unref() 218 let obj = {} 219 function! obj.func() abort 220 endfunction 221 let funcnumber = matchstr(string(obj.func), '^function(''\zs.\{-}\ze''') 222 call assert_true(exists('*{' . funcnumber . '}')) 223 unlet obj 224 call assert_false(exists('*{' . funcnumber . '}')) 225endfunc 226 227func Test_tostring() 228 let d = {} 229 let d.d = d 230 function d.test3() 231 echo 42 232 endfunction 233 try 234 call string(d.test3) 235 catch 236 call assert_true(v:false, v:exception) 237 endtry 238endfunc 239 240func Test_redefine_dict_func() 241 let d = {} 242 function d.test4() 243 endfunction 244 let d.test4 = d.test4 245 try 246 function! d.test4(name) 247 endfunction 248 catch 249 call assert_true(v:errmsg, v:exception) 250 endtry 251endfunc 252 253func Test_bind_in_python() 254 if has('python') 255 let g:d = {} 256 function g:d.test2() 257 endfunction 258 python import vim 259 try 260 call assert_equal(pyeval('vim.bindeval("g:d.test2")'), g:d.test2) 261 catch 262 call assert_true(v:false, v:exception) 263 endtry 264 endif 265endfunc 266 267" This caused double free on exit if EXITFREE is defined. 268func Test_cyclic_list_arg() 269 let l = [] 270 let Pt = function('string', [l]) 271 call add(l, Pt) 272 unlet l 273 unlet Pt 274endfunc 275 276" This caused double free on exit if EXITFREE is defined. 277func Test_cyclic_dict_arg() 278 let d = {} 279 let Pt = function('string', [d]) 280 let d.Pt = Pt 281 unlet d 282 unlet Pt 283endfunc 284 285func Ignored(job1, job2, status) 286endfunc 287 288func Test_cycle_partial_job() 289 if has('job') 290 let job = job_start('echo') 291 call job_setoptions(job, {'exit_cb': function('Ignored', [job])}) 292 unlet job 293 endif 294endfunc 295 296func Test_ref_job_partial_dict() 297 if has('job') 298 let g:ref_job = job_start('echo') 299 let d = {'a': 'b'} 300 call job_setoptions(g:ref_job, {'exit_cb': function('string', [], d)}) 301 endif 302endfunc 303 304func Test_auto_partial_rebind() 305 let dict1 = {'name': 'dict1'} 306 func! dict1.f1() 307 return self.name 308 endfunc 309 let dict1.f2 = function(dict1.f1, dict1) 310 311 call assert_equal('dict1', dict1.f1()) 312 call assert_equal('dict1', dict1['f1']()) 313 call assert_equal('dict1', dict1.f2()) 314 call assert_equal('dict1', dict1['f2']()) 315 316 let dict2 = {'name': 'dict2'} 317 let dict2.f1 = dict1.f1 318 let dict2.f2 = dict1.f2 319 320 call assert_equal('dict2', dict2.f1()) 321 call assert_equal('dict2', dict2['f1']()) 322 call assert_equal('dict1', dict2.f2()) 323 call assert_equal('dict1', dict2['f2']()) 324endfunc 325 326func Test_get_partial_items() 327 let dict = {'name': 'hello'} 328 let args = ["foo", "bar"] 329 let Func = function('MyDictFunc') 330 let Cb = function('MyDictFunc', args, dict) 331 332 call assert_equal(Func, get(Cb, 'func')) 333 call assert_equal('MyDictFunc', get(Cb, 'name')) 334 call assert_equal(args, get(Cb, 'args')) 335 call assert_equal(dict, get(Cb, 'dict')) 336 call assert_fails('call get(Cb, "xxx")', 'E475:') 337 338 call assert_equal(Func, get(Func, 'func')) 339 call assert_equal('MyDictFunc', get(Func, 'name')) 340 call assert_equal([], get(Func, 'args')) 341 call assert_true(empty( get(Func, 'dict'))) 342endfunc 343 344func Test_compare_partials() 345 let d1 = {} 346 let d2 = {} 347 348 function d1.f1() dict 349 endfunction 350 351 function d1.f2() dict 352 endfunction 353 354 let F1 = get(d1, 'f1') 355 let F2 = get(d1, 'f2') 356 357 let F1d1 = function(F1, d1) 358 let F2d1 = function(F2, d2) 359 let F1d1a1 = function(F1d1, [1]) 360 let F1d1a12 = function(F1d1, [1, 2]) 361 let F1a1 = function(F1, [1]) 362 let F1a2 = function(F1, [2]) 363 let F1d2 = function(F1, d2) 364 let d3 = {'f1': F1, 'f2': F2} 365 let F1d3 = function(F1, d3) 366 let F1ad1 = function(F1, [d1]) 367 let F1ad3 = function(F1, [d3]) 368 369 call assert_match('^function(''\d\+'')$', string(F1)) " Not a partial 370 call assert_match('^function(''\d\+'')$', string(F2)) " Not a partial 371 call assert_match('^function(''\d\+'', {.*})$', string(F1d1)) " A partial 372 call assert_match('^function(''\d\+'', {.*})$', string(F2d1)) " A partial 373 call assert_match('^function(''\d\+'', \[.*\])$', string(F1a1)) " No dict 374 375 " != 376 let X = F1 377 call assert_false(F1 != X) " same function 378 let X = F1d1 379 call assert_false(F1d1 != X) " same partial 380 let X = F1d1a1 381 call assert_false(F1d1a1 != X) " same partial 382 let X = F1a1 383 call assert_false(F1a1 != X) " same partial 384 385 call assert_true(F1 != F2) " Different functions 386 call assert_true(F1 != F1d1) " Partial /= non-partial 387 call assert_true(F1d1a1 != F1d1a12) " Different number of arguments 388 call assert_true(F1a1 != F1d1a12) " One has no dict 389 call assert_true(F1a1 != F1a2) " Different arguments 390 call assert_true(F1d2 != F1d1) " Different dictionaries 391 call assert_false(F1d1 != F1d3) " Equal dictionaries, even though d1 isnot d3 392 393 " isnot, option 1 394 call assert_true(F1 isnot# F2) " Different functions 395 call assert_true(F1 isnot# F1d1) " Partial /= non-partial 396 call assert_true(F1d1 isnot# F1d3) " d1 isnot d3, even though d1 == d3 397 call assert_true(F1a1 isnot# F1d1a12) " One has no dict 398 call assert_true(F1a1 isnot# F1a2) " Different number of arguments 399 call assert_true(F1ad1 isnot# F1ad3) " In arguments d1 isnot d3 400 401 " isnot, option 2 402 call assert_true(F1 isnot# F2) " Different functions 403 call assert_true(F1 isnot# F1d1) " Partial /= non-partial 404 call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time 405endfunc 406