Bram Moolenaar | 5deeb3f | 2020-04-05 17:08:17 +0200 | [diff] [blame^] | 1 | " Test various aspects of the Vim9 script language. |
| 2 | |
| 3 | source check.vim |
| 4 | source view_util.vim |
| 5 | |
| 6 | " Check that "lines" inside ":def" results in an "error" message. |
| 7 | func CheckDefFailure(lines, error) |
| 8 | call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') |
| 9 | call assert_fails('so Xdef', a:error, a:lines) |
| 10 | call delete('Xdef') |
| 11 | endfunc |
| 12 | |
| 13 | func CheckScriptFailure(lines, error) |
| 14 | call writefile(a:lines, 'Xdef') |
| 15 | call assert_fails('so Xdef', a:error, a:lines) |
| 16 | call delete('Xdef') |
| 17 | endfunc |
| 18 | |
| 19 | func Test_def_basic() |
| 20 | def SomeFunc(): string |
| 21 | return 'yes' |
| 22 | enddef |
| 23 | call assert_equal('yes', SomeFunc()) |
| 24 | endfunc |
| 25 | |
| 26 | def ReturnString(): string |
| 27 | return 'string' |
| 28 | enddef |
| 29 | |
| 30 | def ReturnNumber(): number |
| 31 | return 123 |
| 32 | enddef |
| 33 | |
| 34 | let g:notNumber = 'string' |
| 35 | |
| 36 | def ReturnGlobal(): number |
| 37 | return g:notNumber |
| 38 | enddef |
| 39 | |
| 40 | def Test_return_something() |
| 41 | assert_equal('string', ReturnString()) |
| 42 | assert_equal(123, ReturnNumber()) |
| 43 | assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string') |
| 44 | enddef |
| 45 | |
| 46 | let s:nothing = 0 |
| 47 | def ReturnNothing() |
| 48 | s:nothing = 1 |
| 49 | if true |
| 50 | return |
| 51 | endif |
| 52 | s:nothing = 2 |
| 53 | enddef |
| 54 | |
| 55 | def Test_return_nothing() |
| 56 | ReturnNothing() |
| 57 | assert_equal(1, s:nothing) |
| 58 | enddef |
| 59 | |
| 60 | func Increment() |
| 61 | let g:counter += 1 |
| 62 | endfunc |
| 63 | |
| 64 | def Test_call_ufunc_count() |
| 65 | g:counter = 1 |
| 66 | Increment() |
| 67 | Increment() |
| 68 | Increment() |
| 69 | " works with and without :call |
| 70 | assert_equal(4, g:counter) |
| 71 | call assert_equal(4, g:counter) |
| 72 | unlet g:counter |
| 73 | enddef |
| 74 | |
| 75 | def MyVarargs(arg: string, ...rest: list<string>): string |
| 76 | let res = arg |
| 77 | for s in rest |
| 78 | res ..= ',' .. s |
| 79 | endfor |
| 80 | return res |
| 81 | enddef |
| 82 | |
| 83 | def Test_call_varargs() |
| 84 | assert_equal('one', MyVarargs('one')) |
| 85 | assert_equal('one,two', MyVarargs('one', 'two')) |
| 86 | assert_equal('one,two,three', MyVarargs('one', 'two', 'three')) |
| 87 | enddef |
| 88 | |
| 89 | def MyDefaultArgs(name = 'string'): string |
| 90 | return name |
| 91 | enddef |
| 92 | |
| 93 | def Test_call_default_args() |
| 94 | assert_equal('string', MyDefaultArgs()) |
| 95 | assert_equal('one', MyDefaultArgs('one')) |
| 96 | assert_fails('call MyDefaultArgs("one", "two")', 'E118:') |
| 97 | |
| 98 | call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') |
| 99 | enddef |
| 100 | |
| 101 | func Test_call_default_args_from_func() |
| 102 | call assert_equal('string', MyDefaultArgs()) |
| 103 | call assert_equal('one', MyDefaultArgs('one')) |
| 104 | call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') |
| 105 | endfunc |
| 106 | |
| 107 | func TakesOneArg(arg) |
| 108 | echo a:arg |
| 109 | endfunc |
| 110 | |
| 111 | def Test_call_wrong_args() |
| 112 | call CheckDefFailure(['TakesOneArg()'], 'E119:') |
| 113 | call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') |
| 114 | call CheckDefFailure(['bufnr(xxx)'], 'E1001:') |
| 115 | enddef |
| 116 | |
| 117 | " Default arg and varargs |
| 118 | def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string |
| 119 | let res = one .. ',' .. two |
| 120 | for s in rest |
| 121 | res ..= ',' .. s |
| 122 | endfor |
| 123 | return res |
| 124 | enddef |
| 125 | |
| 126 | def Test_call_def_varargs() |
| 127 | call assert_fails('call MyDefVarargs()', 'E119:') |
| 128 | assert_equal('one,foo', MyDefVarargs('one')) |
| 129 | assert_equal('one,two', MyDefVarargs('one', 'two')) |
| 130 | assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) |
| 131 | enddef |
| 132 | |
| 133 | def Test_using_var_as_arg() |
| 134 | call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef') |
| 135 | call assert_fails('so Xdef', 'E1006:') |
| 136 | call delete('Xdef') |
| 137 | enddef |
| 138 | |
| 139 | def Test_call_func_defined_later() |
| 140 | call assert_equal('one', DefinedLater('one')) |
| 141 | call assert_fails('call NotDefined("one")', 'E117:') |
| 142 | enddef |
| 143 | |
| 144 | func DefinedLater(arg) |
| 145 | return a:arg |
| 146 | endfunc |
| 147 | |
| 148 | def FuncWithForwardCall() |
| 149 | return DefinedEvenLater("yes") |
| 150 | enddef |
| 151 | |
| 152 | def DefinedEvenLater(arg: string): string |
| 153 | return arg |
| 154 | enddef |
| 155 | |
| 156 | def Test_error_in_nested_function() |
| 157 | " Error in called function requires unwinding the call stack. |
| 158 | assert_fails('call FuncWithForwardCall()', 'E1029') |
| 159 | enddef |
| 160 | |
| 161 | def Test_return_type_wrong() |
| 162 | CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') |
| 163 | CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') |
| 164 | CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') |
| 165 | CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') |
| 166 | |
| 167 | CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:') |
| 168 | |
| 169 | CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') |
| 170 | CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') |
| 171 | enddef |
| 172 | |
| 173 | def Test_arg_type_wrong() |
| 174 | CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') |
| 175 | enddef |
| 176 | |
| 177 | def Test_vim9script_call() |
| 178 | let lines =<< trim END |
| 179 | vim9script |
| 180 | let var = '' |
| 181 | def MyFunc(arg: string) |
| 182 | var = arg |
| 183 | enddef |
| 184 | MyFunc('foobar') |
| 185 | assert_equal('foobar', var) |
| 186 | |
| 187 | let str = 'barfoo' |
| 188 | str->MyFunc() |
| 189 | assert_equal('barfoo', var) |
| 190 | |
| 191 | let g:value = 'value' |
| 192 | g:value->MyFunc() |
| 193 | assert_equal('value', var) |
| 194 | |
| 195 | let listvar = [] |
| 196 | def ListFunc(arg: list<number>) |
| 197 | listvar = arg |
| 198 | enddef |
| 199 | [1, 2, 3]->ListFunc() |
| 200 | assert_equal([1, 2, 3], listvar) |
| 201 | |
| 202 | let dictvar = {} |
| 203 | def DictFunc(arg: dict<number>) |
| 204 | dictvar = arg |
| 205 | enddef |
| 206 | {'a': 1, 'b': 2}->DictFunc() |
| 207 | assert_equal(#{a: 1, b: 2}, dictvar) |
| 208 | def CompiledDict() |
| 209 | {'a': 3, 'b': 4}->DictFunc() |
| 210 | enddef |
| 211 | CompiledDict() |
| 212 | assert_equal(#{a: 3, b: 4}, dictvar) |
| 213 | |
| 214 | #{a: 3, b: 4}->DictFunc() |
| 215 | assert_equal(#{a: 3, b: 4}, dictvar) |
| 216 | |
| 217 | ('text')->MyFunc() |
| 218 | assert_equal('text', var) |
| 219 | ("some")->MyFunc() |
| 220 | assert_equal('some', var) |
| 221 | END |
| 222 | writefile(lines, 'Xcall.vim') |
| 223 | source Xcall.vim |
| 224 | delete('Xcall.vim') |
| 225 | enddef |
| 226 | |
| 227 | def Test_vim9script_call_fail_decl() |
| 228 | let lines =<< trim END |
| 229 | vim9script |
| 230 | let var = '' |
| 231 | def MyFunc(arg: string) |
| 232 | let var = 123 |
| 233 | enddef |
| 234 | END |
| 235 | writefile(lines, 'Xcall_decl.vim') |
| 236 | assert_fails('source Xcall_decl.vim', 'E1054:') |
| 237 | delete('Xcall_decl.vim') |
| 238 | enddef |
| 239 | |
| 240 | def Test_vim9script_call_fail_const() |
| 241 | let lines =<< trim END |
| 242 | vim9script |
| 243 | const var = '' |
| 244 | def MyFunc(arg: string) |
| 245 | var = 'asdf' |
| 246 | enddef |
| 247 | END |
| 248 | writefile(lines, 'Xcall_const.vim') |
| 249 | assert_fails('source Xcall_const.vim', 'E46:') |
| 250 | delete('Xcall_const.vim') |
| 251 | enddef |
| 252 | |
| 253 | " Test that inside :function a Python function can be defined, :def is not |
| 254 | " recognized. |
| 255 | func Test_function_python() |
| 256 | CheckFeature python3 |
| 257 | let py = 'python3' |
| 258 | execute py "<< EOF" |
| 259 | def do_something(): |
| 260 | return 1 |
| 261 | EOF |
| 262 | endfunc |
| 263 | |
| 264 | def Test_delfunc() |
| 265 | let lines =<< trim END |
| 266 | vim9script |
| 267 | def GoneSoon() |
| 268 | echo 'hello' |
| 269 | enddef |
| 270 | |
| 271 | def CallGoneSoon() |
| 272 | GoneSoon() |
| 273 | enddef |
| 274 | |
| 275 | delfunc GoneSoon |
| 276 | CallGoneSoon() |
| 277 | END |
| 278 | writefile(lines, 'XToDelFunc') |
| 279 | assert_fails('so XToDelFunc', 'E933') |
| 280 | assert_fails('so XToDelFunc', 'E933') |
| 281 | |
| 282 | delete('XToDelFunc') |
| 283 | enddef |
| 284 | |
| 285 | def Test_redef_failure() |
| 286 | call writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') |
| 287 | so Xdef |
| 288 | call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') |
| 289 | so Xdef |
| 290 | call writefile(['def! Func0(): string', 'enddef'], 'Xdef') |
| 291 | call assert_fails('so Xdef', 'E1027:') |
| 292 | call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') |
| 293 | so Xdef |
| 294 | call delete('Xdef') |
| 295 | |
| 296 | call assert_equal(0, Func0()) |
| 297 | call assert_equal('Func1', Func1()) |
| 298 | call assert_equal('Func2', Func2()) |
| 299 | |
| 300 | delfunc! Func0 |
| 301 | delfunc! Func1 |
| 302 | delfunc! Func2 |
| 303 | enddef |
| 304 | |
| 305 | " Test for internal functions returning different types |
| 306 | func Test_InternalFuncRetType() |
| 307 | let lines =<< trim END |
| 308 | def RetFloat(): float |
| 309 | return ceil(1.456) |
| 310 | enddef |
| 311 | |
| 312 | def RetListAny(): list<any> |
| 313 | return items({'k' : 'v'}) |
| 314 | enddef |
| 315 | |
| 316 | def RetListString(): list<string> |
| 317 | return split('a:b:c', ':') |
| 318 | enddef |
| 319 | |
| 320 | def RetListDictAny(): list<dict<any>> |
| 321 | return getbufinfo() |
| 322 | enddef |
| 323 | |
| 324 | def RetDictNumber(): dict<number> |
| 325 | return wordcount() |
| 326 | enddef |
| 327 | |
| 328 | def RetDictString(): dict<string> |
| 329 | return environ() |
| 330 | enddef |
| 331 | END |
| 332 | call writefile(lines, 'Xscript') |
| 333 | source Xscript |
| 334 | |
| 335 | call assert_equal(2.0, RetFloat()) |
| 336 | call assert_equal([['k', 'v']], RetListAny()) |
| 337 | call assert_equal(['a', 'b', 'c'], RetListString()) |
| 338 | call assert_notequal([], RetListDictAny()) |
| 339 | call assert_notequal({}, RetDictNumber()) |
| 340 | call assert_notequal({}, RetDictString()) |
| 341 | call delete('Xscript') |
| 342 | endfunc |
| 343 | |
| 344 | " Test for passing too many or too few arguments to internal functions |
| 345 | func Test_internalfunc_arg_error() |
| 346 | let l =<< trim END |
| 347 | def! FArgErr(): float |
| 348 | return ceil(1.1, 2) |
| 349 | enddef |
| 350 | END |
| 351 | call writefile(l, 'Xinvalidarg') |
| 352 | call assert_fails('so Xinvalidarg', 'E118:') |
| 353 | let l =<< trim END |
| 354 | def! FArgErr(): float |
| 355 | return ceil() |
| 356 | enddef |
| 357 | END |
| 358 | call writefile(l, 'Xinvalidarg') |
| 359 | call assert_fails('so Xinvalidarg', 'E119:') |
| 360 | call delete('Xinvalidarg') |
| 361 | endfunc |
| 362 | |
| 363 | let s:funcResult = 0 |
| 364 | |
| 365 | def FuncNoArgNoRet() |
| 366 | funcResult = 11 |
| 367 | enddef |
| 368 | |
| 369 | def FuncNoArgRetNumber(): number |
| 370 | funcResult = 22 |
| 371 | return 1234 |
| 372 | enddef |
| 373 | |
| 374 | def FuncOneArgNoRet(arg: number) |
| 375 | funcResult = arg |
| 376 | enddef |
| 377 | |
| 378 | def FuncOneArgRetNumber(arg: number): number |
| 379 | funcResult = arg |
| 380 | return arg |
| 381 | enddef |
| 382 | |
| 383 | def Test_func_type() |
| 384 | let Ref1: func() |
| 385 | funcResult = 0 |
| 386 | Ref1 = FuncNoArgNoRet |
| 387 | Ref1() |
| 388 | assert_equal(11, funcResult) |
| 389 | enddef |
| 390 | |
| 391 | def Test_func_type_fails() |
| 392 | CheckDefFailure(['let ref1: func()'], 'E704:') |
| 393 | |
| 394 | CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') |
| 395 | CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)') |
| 396 | CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number') |
| 397 | enddef |
| 398 | |
| 399 | |
| 400 | " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker |