diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-03 22:21:25 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-04 00:23:03 +0300 |
| commit | 2eae5db069dc171f74cd863487655f6a88e5384d (patch) | |
| tree | 2d9d05e09978a2a44acbfbb8d651f240df3ca052 /uvim/src/testdir/test_vim9_script.vim | |
| parent | 473d922faed49241a5d29d9e37dc4819cd512006 (diff) | |
| download | Project-Tick-2eae5db069dc171f74cd863487655f6a88e5384d.tar.gz Project-Tick-2eae5db069dc171f74cd863487655f6a88e5384d.zip | |
NOISSUE rebrand vim to MNV's not Vim
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'uvim/src/testdir/test_vim9_script.vim')
| -rw-r--r-- | uvim/src/testdir/test_vim9_script.vim | 5828 |
1 files changed, 0 insertions, 5828 deletions
diff --git a/uvim/src/testdir/test_vim9_script.vim b/uvim/src/testdir/test_vim9_script.vim deleted file mode 100644 index eefb6174d8..0000000000 --- a/uvim/src/testdir/test_vim9_script.vim +++ /dev/null @@ -1,5828 +0,0 @@ -" Test various aspects of the Vim9 script language. - -import './util/vim9.vim' as v9 -source util/screendump.vim - -def Test_vim9script_feature() - # example from the help, here the feature is always present - var lines =<< trim END - " old style comment - if !has('vim9script') - " legacy commands would go here - finish - endif - vim9script - # Vim9 script commands go here - g:didit = true - END - v9.CheckScriptSuccess(lines) - assert_equal(true, g:didit) - unlet g:didit -enddef - -def Test_range_only() - new - setline(1, ['blah', 'Blah']) - :/Blah/ - assert_equal(2, getcurpos()[1]) - bwipe! - - # without range commands use current line - new - setline(1, ['one', 'two', 'three']) - :2 - print - assert_equal('two', g:Screenline(&lines)) - :3 - list - assert_equal('three$', g:Screenline(&lines)) - - # missing command does not print the line - var lines =<< trim END - vim9script - :1| - assert_equal('three$', g:Screenline(&lines)) - :| - assert_equal('three$', g:Screenline(&lines)) - END - v9.CheckScriptSuccess(lines) - - bwipe! - - lines =<< trim END - set cpo+=- - :1,999 - END - v9.CheckDefExecAndScriptFailure(lines, 'E16:', 2) - set cpo&vim - - v9.CheckDefExecAndScriptFailure([":'x"], 'E20:', 1) - - # won't generate anything - if false - :123 - endif -enddef - -def Test_invalid_range() - var lines =<< trim END - :123 eval 1 + 2 - END - v9.CheckDefAndScriptFailure(lines, 'E481:', 1) - - lines =<< trim END - :123 if true - endif - END - v9.CheckDefAndScriptFailure(lines, 'E481:', 1) - - lines =<< trim END - :123 echo 'yes' - END - v9.CheckDefAndScriptFailure(lines, 'E481:', 1) - - lines =<< trim END - :123 cd there - END - v9.CheckDefAndScriptFailure(lines, 'E481:', 1) -enddef - -let g:alist = [7] -let g:astring = 'text' -let g:anumber = 123 - -def Test_delfunction() - # Check function is defined in script namespace - v9.CheckScriptSuccess([ - 'vim9script', - 'func CheckMe()', - ' return 123', - 'endfunc', - 'func DoTest()', - ' call assert_equal(123, s:CheckMe())', - 'endfunc', - 'DoTest()', - ]) - - # Check function in script namespace cannot be deleted - v9.CheckScriptFailure([ - 'vim9script', - 'func DeleteMe1()', - 'endfunc', - 'delfunction DeleteMe1', - ], 'E1084:') - v9.CheckScriptFailure([ - 'vim9script', - 'func DeleteMe2()', - 'endfunc', - 'def DoThat()', - ' delfunction DeleteMe2', - 'enddef', - 'DoThat()', - ], 'E1084:') - v9.CheckScriptFailure([ - 'vim9script', - 'def DeleteMe3()', - 'enddef', - 'delfunction DeleteMe3', - ], 'E1084:') - v9.CheckScriptFailure([ - 'vim9script', - 'def DeleteMe4()', - 'enddef', - 'def DoThat()', - ' delfunction DeleteMe4', - 'enddef', - 'DoThat()', - ], 'E1084:') - - # Check that global :def function can be replaced and deleted - var lines =<< trim END - vim9script - def g:Global(): string - return "yes" - enddef - assert_equal("yes", g:Global()) - def! g:Global(): string - return "no" - enddef - assert_equal("no", g:Global()) - delfunc g:Global - assert_false(exists('*g:Global')) - END - v9.CheckScriptSuccess(lines) - - # Check that global function can be replaced by a :def function and deleted - lines =<< trim END - vim9script - func g:Global() - return "yes" - endfunc - assert_equal("yes", g:Global()) - def! g:Global(): string - return "no" - enddef - assert_equal("no", g:Global()) - delfunc g:Global - assert_false(exists('*g:Global')) - END - v9.CheckScriptSuccess(lines) - - # Check that global :def function can be replaced by a function and deleted - lines =<< trim END - vim9script - def g:Global(): string - return "yes" - enddef - assert_equal("yes", g:Global()) - func! g:Global() - return "no" - endfunc - assert_equal("no", g:Global()) - delfunc g:Global - assert_false(exists('*g:Global')) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_wrong_type() - v9.CheckDefFailure(['var name: list<nothing>'], 'E1010:') - v9.CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:') - v9.CheckDefFailure(['var name: dict<nothing>'], 'E1010:') - v9.CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:') - - v9.CheckDefFailure(['var name: dict<number'], 'E1009:') - v9.CheckDefFailure(['var name: dict<list<number>'], 'E1009:') - - v9.CheckDefFailure(['var name: ally'], 'E1010:') - v9.CheckDefFailure(['var name: bram'], 'E1010:') - v9.CheckDefFailure(['var name: cathy'], 'E1010:') - v9.CheckDefFailure(['var name: dom'], 'E1010:') - v9.CheckDefFailure(['var name: freddy'], 'E1010:') - v9.CheckDefFailure(['var name: john'], 'E1010:') - v9.CheckDefFailure(['var name: larry'], 'E1010:') - v9.CheckDefFailure(['var name: ned'], 'E1010:') - v9.CheckDefFailure(['var name: pam'], 'E1010:') - v9.CheckDefFailure(['var name: sam'], 'E1010:') - v9.CheckDefFailure(['var name: vim'], 'E1010:') - - v9.CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:') - v9.CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:') -enddef - -def Test_script_namespace() - # defining a function or variable with s: is not allowed - var lines =<< trim END - vim9script - def s:Function() - enddef - END - v9.CheckScriptFailure(lines, 'E1268:') - - for decl in ['var', 'const', 'final'] - lines =<< trim END - vim9script - var s:var = 'var' - END - v9.CheckScriptFailure([ - 'vim9script', - decl .. ' s:var = "var"', - ], 'E1268:') - endfor - - # Calling a function or using a variable with s: is not allowed at script - # level - lines =<< trim END - vim9script - def Function() - enddef - s:Function() - END - v9.CheckScriptFailure(lines, 'E1268:') - lines =<< trim END - vim9script - def Function() - enddef - call s:Function() - END - v9.CheckScriptFailure(lines, 'E1268:') - lines =<< trim END - vim9script - var var = 'var' - echo s:var - END - v9.CheckScriptFailure(lines, 'E1268:') -enddef - -def Test_script_wrong_type() - var lines =<< trim END - vim9script - var dict: dict<string> - dict['a'] = ['x'] - END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3) -enddef - -def Test_const() - v9.CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:') - v9.CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:') - v9.CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:') - v9.CheckDefFailure(['final two'], 'E1125:') - v9.CheckDefFailure(['final &option'], 'E996:') - - var lines =<< trim END - final list = [1, 2, 3] - list[0] = 4 - list->assert_equal([4, 2, 3]) - const other = [5, 6, 7] - other->assert_equal([5, 6, 7]) - - var varlist = [7, 8] - const constlist = [1, varlist, 3] - varlist[0] = 77 - constlist[1][1] = 88 - var cl = constlist[1] - cl[1] = 88 - constlist->assert_equal([1, [77, 88], 3]) - - var vardict = {five: 5, six: 6} - const constdict = {one: 1, two: vardict, three: 3} - vardict['five'] = 55 - constdict['two']['six'] = 66 - var cd = constdict['two'] - cd['six'] = 66 - constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3}) - END - v9.CheckDefAndScriptSuccess(lines) - - # "any" type with const flag is recognized as "any" - lines =<< trim END - const dict: dict<any> = {foo: {bar: 42}} - const foo = dict.foo - assert_equal(v:t_number, type(foo.bar)) - END - v9.CheckDefAndScriptSuccess(lines) - - # also when used as a builtin function argument - lines =<< trim END - vim9script - - def SorterFunc(lhs: dict<string>, rhs: dict<string>): number - return lhs.name <# rhs.name ? -1 : 1 - enddef - - def Run(): void - var list = [{name: "3"}, {name: "2"}] - const Sorter = get({}, "unknown", SorterFunc) - sort(list, Sorter) - assert_equal([{name: "2"}, {name: "3"}], list) - enddef - - Run() - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_const_bang() - var lines =<< trim END - const var = 234 - var = 99 - END - v9.CheckDefExecFailure(lines, 'E1018:', 2) - v9.CheckScriptFailure(['vim9script'] + lines, 'E46:', 3) - - lines =<< trim END - const ll = [2, 3, 4] - ll[0] = 99 - END - v9.CheckDefExecFailure(lines, 'E1119:', 2) - v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) - - lines =<< trim END - const ll = [2, 3, 4] - ll[3] = 99 - END - v9.CheckDefExecFailure(lines, 'E1118:', 2) - v9.CheckScriptFailure(['vim9script'] + lines, 'E684:', 3) - - lines =<< trim END - const dd = {one: 1, two: 2} - dd["one"] = 99 - END - v9.CheckDefExecFailure(lines, 'E1121:', 2) - v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) - - lines =<< trim END - const dd = {one: 1, two: 2} - dd["three"] = 99 - END - v9.CheckDefExecFailure(lines, 'E1120:') - v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) -enddef - -def Test_range_no_colon() - v9.CheckDefFailure(['%s/a/b/'], 'E1050:') - v9.CheckDefFailure(['+ s/a/b/'], 'E1050:') - v9.CheckDefFailure(['- s/a/b/'], 'E1050:') - v9.CheckDefFailure(['. s/a/b/'], 'E1050:') -enddef - - -def Test_block() - var outer = 1 - { - var inner = 2 - assert_equal(1, outer) - assert_equal(2, inner) - } - assert_equal(1, outer) - - {|echo 'yes'|} -enddef - -def Test_block_failure() - v9.CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:') - v9.CheckDefFailure(['}'], 'E1025:') - v9.CheckDefFailure(['{', 'echo 1'], 'E1026:') -enddef - -def Test_block_local_vars() - var lines =<< trim END - vim9script - v:testing = 1 - if true - var text = ['hello'] - def SayHello(): list<string> - return text - enddef - def SetText(v: string) - text = [v] - enddef - endif - - if true - var text = ['again'] - def SayAgain(): list<string> - return text - enddef - endif - - # test that the "text" variables are not cleaned up - test_garbagecollect_now() - - defcompile - - assert_equal(['hello'], SayHello()) - assert_equal(['again'], SayAgain()) - - SetText('foobar') - assert_equal(['foobar'], SayHello()) - - call writefile(['ok'], 'Xdidit') - qall! - END - - # need to execute this with a separate Vim instance to avoid the current - # context gets garbage collected. - writefile(lines, 'Xscript', 'D') - g:RunVim([], [], '-S Xscript') - assert_equal(['ok'], readfile('Xdidit')) - - delete('Xdidit') -enddef - -def Test_block_local_vars_with_func() - var lines =<< trim END - vim9script - if true - var foo = 'foo' - if true - var bar = 'bar' - def Func(): list<string> - return [foo, bar] - enddef - endif - endif - # function is compiled here, after blocks have finished, can still access - # "foo" and "bar" - assert_equal(['foo', 'bar'], Func()) - END - v9.CheckScriptSuccess(lines) -enddef - -" legacy func for command that's defined later -func s:InvokeSomeCommand() - SomeCommand -endfunc - -def Test_command_block() - com SomeCommand { - g:someVar = 'some' - } - InvokeSomeCommand() - assert_equal('some', g:someVar) - - delcommand SomeCommand - unlet g:someVar -enddef - -" Test for using heredoc in a :command command block -def Test_command_block_heredoc() - var lines =<< trim CODE - vim9script - com SomeCommand { - g:someVar =<< trim END - aaa - bbb - END - } - SomeCommand - assert_equal(['aaa', 'bbb'], g:someVar) - def Foo() - g:someVar = [] - SomeCommand - assert_equal(['aaa', 'bbb'], g:someVar) - enddef - Foo() - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess( lines) - - # Execute a command with heredoc in a block - lines =<< trim CODE - vim9script - com SomeCommand { - g:someVar =<< trim END - aaa - bbb - END - } - execute('SomeCommand') - assert_equal(['aaa', 'bbb'], g:someVar) - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess(lines) - - # Heredoc with comment - lines =<< trim CODE - vim9script - com SomeCommand { - g:someVar =<< trim END # comment - aaa - bbb - END - } - execute('SomeCommand') - assert_equal(['aaa', 'bbb'], g:someVar) - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess(lines) - - # heredoc evaluation - lines =<< trim CODE - vim9script - com SomeCommand { - var suffix = '---' - g:someVar =<< trim eval END - ccc{suffix} - ddd - END - } - SomeCommand - assert_equal(['ccc---', 'ddd'], g:someVar) - def Foo() - g:someVar = [] - SomeCommand - assert_equal(['ccc---', 'ddd'], g:someVar) - enddef - Foo() - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess(lines) - - # command following heredoc - lines =<< trim CODE - vim9script - com SomeCommand { - var l =<< trim END - eee - fff - END - g:someVar = l - } - SomeCommand - assert_equal(['eee', 'fff'], g:someVar) - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess(lines) - - # Error in heredoc - lines =<< trim CODE - vim9script - com SomeCommand { - g:someVar =<< trim END - eee - fff - } - try - SomeCommand - catch - assert_match("E990: Missing end marker 'END'", v:exception) - endtry - delcommand SomeCommand - unlet g:someVar - CODE - v9.CheckSourceSuccess(lines) -enddef - -def Test_autocommand_block() - au BufNew *.xml { - g:otherVar = 'other' - } - split other.xml - assert_equal('other', g:otherVar) - - bwipe! - au! BufNew *.xml - unlet g:otherVar -enddef - -def Test_block_in_a_string() - var lines =<< trim END - vim9script - - def Foo(): string - var x = ' => { # abc' - return x - enddef - - assert_equal(' => { # abc', Foo()) - - def Bar(): string - var x = " => { # abc" - return x - enddef - - assert_equal(" => { # abc", Bar()) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for a block in a command with comments -def Test_block_command_with_comment() - var lines =<< trim END - vim9script - - g:Str = '' - command Cmd1 { - g:Str = 'Hello' # comment1 - var x: string # comment2 - g:Str ..= ' World' # comment3 - } - Cmd1 - assert_equal('Hello World', g:Str) - - g:Str = '' - command Cmd2 { - # comment1 - g:Str = 'Hello' - # comment2 - g:Str ..= ' World' - # comment3 - } - Cmd2 - assert_equal('Hello World', g:Str) - - command Cmd3 { - new # comment1 - setline(1, 'hello') # comment2 - } - Cmd3 - assert_equal(['hello'], getline(1, '$')) - :bw! - - command Cmd4 { - # comment1 - new - # comment2 - setline(1, 'hello') # comment2 - } - Cmd4 - assert_equal(['hello'], getline(1, '$')) - :bw! - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using too many nested blocks -def Test_too_many_nested_blocks() - var lines = ['vim9script'] - lines += repeat(['{'], 51) + ['echo "Hello"'] + repeat(['}'], 51) - v9.CheckSourceFailure(lines, 'E579: Block nesting too deep: {') -enddef - -func g:NoSuchFunc() - echo 'none' -endfunc - -def Test_try_catch_throw() - var l = [] - try # comment - add(l, '1') - throw 'wrong' - add(l, '2') # "unreachable code" - catch # comment - add(l, v:exception) - finally # comment - add(l, '3') - endtry # comment - assert_equal(['1', 'wrong', '3'], l) - - l = [] - try - try - add(l, '1') - throw 'wrong' - add(l, '2') # "unreachable code" - catch /right/ - add(l, v:exception) - endtry - catch /wrong/ - add(l, 'caught') - finally - add(l, 'finally') - endtry - assert_equal(['1', 'caught', 'finally'], l) - - var n: number - try - n = l[3] - catch /E684:/ - n = 99 - endtry - assert_equal(99, n) - - var done = 'no' - if 0 - try | catch | endtry - else - done = 'yes' - endif - assert_equal('yes', done) - - done = 'no' - if 1 - done = 'yes' - else - try | catch | endtry - done = 'never' - endif - assert_equal('yes', done) - - if 1 - else - try | catch /pat/ | endtry - try | catch /pat/ - endtry - try - catch /pat/ | endtry - try - catch /pat/ - endtry - endif - - try - # string slice returns a string, not a number - n = g:astring[3] - catch /E1012:/ - n = 77 - endtry - assert_equal(77, n) - - try - n = l[g:astring] - catch /E1012:/ - n = 88 - endtry - assert_equal(88, n) - - try - n = s:does_not_exist - catch /E121:/ - n = 111 - endtry - assert_equal(111, n) - - try - n = g:does_not_exist - catch /E121:/ - n = 121 - endtry - assert_equal(121, n) - - var d = {one: 1} - try - n = d[g:astring] - catch /E716:/ - n = 222 - endtry - assert_equal(222, n) - - try - n = -g:astring - catch /E1012:/ - n = 233 - endtry - assert_equal(233, n) - - try - n = +g:astring - catch /E1012:/ - n = 244 - endtry - assert_equal(244, n) - - try - n = +g:alist - catch /E1012:/ - n = 255 - endtry - assert_equal(255, n) - - var nd: dict<any> - try - nd = {[g:alist]: 1} - catch /E1105:/ - n = 266 - endtry - assert_equal(266, n) - - l = [1, 2, 3] - try - [n] = l - catch /E1093:/ - n = 277 - endtry - assert_equal(277, n) - - try - &ts = g:astring - catch /E1012:/ - n = 288 - endtry - assert_equal(288, n) - - try - &backspace = 'asdf' - catch /E474:/ - n = 299 - endtry - assert_equal(299, n) - - l = [1] - try - l[3] = 3 - catch /E684:/ - n = 300 - endtry - assert_equal(300, n) - - try - unlet g:does_not_exist - catch /E108:/ - n = 322 - endtry - assert_equal(322, n) - - try - d = {text: 1, [g:astring]: 2} - catch /E721:/ - n = 333 - endtry - assert_equal(333, n) - - try - l = g:DeletedFunc() - catch /E933:/ - n = 344 - endtry - assert_equal(344, n) - - try - echo range(1, 2, 0) - catch /E726:/ - n = 355 - endtry - assert_equal(355, n) - - var P = function('g:NoSuchFunc') - delfunc g:NoSuchFunc - try - echo P() - catch /E117:/ - n = 366 - endtry - assert_equal(366, n) - - try - echo g:NoSuchFunc() - catch /E117:/ - n = 377 - endtry - assert_equal(377, n) - - try - echo g:alist + 4 - catch /E745:/ - n = 388 - endtry - assert_equal(388, n) - - try - echo 4 + g:alist - catch /E745:/ - n = 399 - endtry - assert_equal(399, n) - - try - echo g:alist.member - catch /E715:/ - n = 400 - endtry - assert_equal(400, n) - - try - echo d.member - catch /E716:/ - n = 411 - endtry - assert_equal(411, n) - - var counter = 0 - for i in range(4) - try - eval [][0] - catch - endtry - counter += 1 - endfor - assert_equal(4, counter) - - # no requirement for spaces before | - try|echo 0|catch|endtry - - # return in try with finally - def ReturnInTry(): number - var ret = 4 - try - return ret - catch /this/ - return -1 - catch /that/ - return -1 - finally - # changing ret has no effect - ret = 7 - endtry - return -2 - enddef - assert_equal(4, ReturnInTry()) - - # return in catch with finally - def ReturnInCatch(): number - var ret = 5 - try - throw 'getout' - return -1 # "unreachable code" - catch /getout/ - # ret is evaluated here - return ret - finally - # changing ret later has no effect - ret = -3 - endtry - return -2 - enddef - assert_equal(5, ReturnInCatch()) - - # return in finally after empty catch - def ReturnInFinally(): number - try - finally - return 6 - endtry - enddef - assert_equal(6, ReturnInFinally()) - - var lines =<< trim END - vim9script - try - acos('0.5') - ->setline(1) - catch - g:caught = v:exception - endtry - END - v9.CheckScriptSuccess(lines) - assert_match('E1219: Float or Number required for argument 1', g:caught) - unlet g:caught - - # missing catch and/or finally - lines =<< trim END - vim9script - try - echo 'something' - endtry - END - v9.CheckScriptFailure(lines, 'E1032:') - - # skipping try-finally-endtry when try-finally-endtry is used in another block - lines =<< trim END - if v:true - try - finally - endtry - else - try - finally - endtry - endif - END - v9.CheckDefAndScriptSuccess(lines) - - # test that the v:exception stacks are correctly restored - try - try - throw 101 - catch - assert_equal('101', v:exception) - try - catch - finally - assert_equal('101', v:exception) # finally shouldn't clear if it doesn't own it - endtry - assert_equal('101', v:exception) - throw 102 # Re-throw inside catch block - endtry - catch - assert_equal('102', v:exception) - try - throw 103 # throw inside nested exception stack - catch - assert_equal('103', v:exception) - endtry - assert_equal('102', v:exception) # restored stack - finally - assert_equal('', v:exception) # finally should clear if it owns the exception - endtry - try - try - throw 104 - catch - try - exec 'nonexistent_cmd' # normal exception inside nested exception stack - catch - assert_match('E492:', v:exception) - endtry - eval [][0] # normal exception inside catch block - endtry - catch - assert_match('E684:', v:exception) - endtry - assert_equal('', v:exception) # All exceptions properly popped -enddef - -def Test_unreachable_after() - var lines =<< trim END - try - throw 'Error' - echo 'not reached' - catch /Error/ - endtry - END - v9.CheckDefFailure(lines, 'E1095: Unreachable code after :throw') - - lines =<< trim END - def SomeFunc(): number - try - return 3 - echo 'not reached' - catch /Error/ - endtry - return 4 - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1095: Unreachable code after :return') -enddef - -def Test_throw_in_nested_try() - var lines =<< trim END - vim9script - - def Try(F: func(): void) - try - F() - catch - endtry - enddef - - class X - def F() - try - throw 'Foobar' - catch - throw v:exception - endtry - enddef - endclass - - def Test_TryMethod() - var x = X.new() - Try(() => x.F()) - enddef - - - try - Test_TryMethod() - catch - endtry - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_try_var_decl() - var lines =<< trim END - vim9script - try - var in_try = 1 - assert_equal(1, get(s:, 'in_try', -1)) - throw "getout" - catch - var in_catch = 2 - assert_equal(-1, get(s:, 'in_try', -1)) - assert_equal(2, get(s:, 'in_catch', -1)) - finally - var in_finally = 3 - assert_equal(-1, get(s:, 'in_try', -1)) - assert_equal(-1, get(s:, 'in_catch', -1)) - assert_equal(3, get(s:, 'in_finally', -1)) - endtry - assert_equal(-1, get(s:, 'in_try', -1)) - assert_equal(-1, get(s:, 'in_catch', -1)) - assert_equal(-1, get(s:, 'in_finally', -1)) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_try_ends_in_return() - var lines =<< trim END - vim9script - def Foo(): string - try - return 'foo' - catch - return 'caught' - endtry - enddef - assert_equal('foo', Foo()) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - def Foo(): string - try - return 'foo' - catch - return 'caught' - endtry - echo 'notreached' - enddef - assert_equal('foo', Foo()) - END - v9.CheckScriptFailure(lines, 'E1095:') - - lines =<< trim END - vim9script - def Foo(): string - try - return 'foo' - catch /x/ - return 'caught' - endtry - enddef - assert_equal('foo', Foo()) - END - v9.CheckScriptFailure(lines, 'E1027:') - - lines =<< trim END - vim9script - def Foo(): string - try - echo 'foo' - catch - echo 'caught' - finally - return 'done' - endtry - enddef - assert_equal('done', Foo()) - END - v9.CheckScriptSuccess(lines) - -enddef - -def Test_try_in_catch() - var lines =<< trim END - vim9script - var seq = [] - def DoIt() - try - seq->add('throw 1') - eval [][0] - seq->add('notreached') - catch - seq->add('catch') - try - seq->add('throw 2') - eval [][0] - seq->add('notreached') - catch /nothing/ - seq->add('notreached') - endtry - seq->add('done') - endtry - enddef - DoIt() - assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq) - END -enddef - -def Test_error_in_catch() - var lines =<< trim END - try - eval [][0] - catch /E684:/ - eval [][0] - endtry - END - v9.CheckDefExecFailure(lines, 'E684:', 4) -enddef - -" :while at the very start of a function that :continue jumps to -def s:TryContinueFunc() - while g:Count < 2 - g:sequence ..= 't' - try - echoerr 'Test' - catch - g:Count += 1 - g:sequence ..= 'c' - continue - endtry - g:sequence ..= 'e' - g:Count += 1 - endwhile -enddef - -def Test_continue_in_try_in_while() - g:Count = 0 - g:sequence = '' - TryContinueFunc() - assert_equal('tctc', g:sequence) - unlet g:Count - unlet g:sequence -enddef - -def Test_break_in_try_in_for() - var lines =<< trim END - vim9script - def Ls(): list<string> - var ls: list<string> - for s in ['abc', 'def'] - for _ in [123, 456] - try - eval [][0] - catch - break - endtry - endfor - ls += [s] - endfor - return ls - enddef - assert_equal(['abc', 'def'], Ls()) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_nocatch_return_in_try() - # return in try block returns normally - def ReturnInTry(): string - try - return '"some message"' - catch - endtry - return 'not reached' - enddef - exe 'echoerr ' .. ReturnInTry() -enddef - -def Test_cnext_works_in_catch() - CheckFeature quickfix - var lines =<< trim END - vim9script - au BufEnter * eval 1 + 2 - writefile(['text'], 'Xcncfile1') - writefile(['text'], 'Xcncfile2') - var items = [ - {lnum: 1, filename: 'Xcncfile1', valid: true}, - {lnum: 1, filename: 'Xcncfile2', valid: true} - ] - setqflist([], ' ', {items: items}) - cwindow - - def CnextOrCfirst() - # if cnext fails, cfirst is used - try - cnext - catch - cfirst - endtry - enddef - - CnextOrCfirst() - CnextOrCfirst() - writefile([getqflist({idx: 0}).idx], 'Xcncresult') - qall - END - writefile(lines, 'XCatchCnext', 'D') - g:RunVim([], [], '--clean -S XCatchCnext') - assert_equal(['1'], readfile('Xcncresult')) - - delete('Xcncfile1') - delete('Xcncfile2') - delete('Xcncresult') -enddef - -def Test_throw_skipped() - if 0 - throw dontgethere - endif -enddef - -def Test_nocatch_throw_silenced() - var lines =<< trim END - vim9script - def Func() - throw 'error' - enddef - silent! Func() - END - writefile(lines, 'XthrowSilenced', 'D') - source XthrowSilenced -enddef - -" g:DeletedFunc() is found when compiling Test_try_catch_throw() and then -" deleted, this should give a runtime error. -def DeletedFunc(): list<any> - return ['delete me'] -enddef -defcompile DeletedFunc - -call test_override('unreachable', 1) -defcompile Test_try_catch_throw -call test_override('unreachable', 0) - -delfunc DeletedFunc - -def s:ThrowFromDef() - throw "getout" # comment -enddef - -func s:CatchInFunc() - try - call s:ThrowFromDef() - catch - let g:thrown_func = v:exception - endtry -endfunc - -def s:CatchInDef() - try - ThrowFromDef() - catch - g:thrown_def = v:exception - endtry -enddef - -def s:ReturnFinally(): string - try - return 'intry' - finally - g:in_finally = 'finally' - endtry - return 'end' -enddef - -def Test_try_catch_nested() - CatchInFunc() - assert_equal('getout', g:thrown_func) - - CatchInDef() - assert_equal('getout', g:thrown_def) - - assert_equal('intry', ReturnFinally()) - assert_equal('finally', g:in_finally) - - var l = [] - try - l->add('1') - throw 'bad' - l->add('x') # "unreachable code" - catch /bad/ - l->add('2') - try - l->add('3') - throw 'one' - l->add('x') - catch /one/ - l->add('4') - try - l->add('5') - throw 'more' - l->add('x') - catch /more/ - l->add('6') - endtry - endtry - endtry - assert_equal(['1', '2', '3', '4', '5', '6'], l) - - l = [] - try - try - l->add('1') - throw 'foo' - l->add('x') - catch - l->add('2') - throw 'bar' - l->add('x') - finally - l->add('3') - endtry - l->add('x') - catch /bar/ - l->add('4') - endtry - assert_equal(['1', '2', '3', '4'], l) -enddef - -call test_override('unreachable', 1) -defcompile Test_try_catch_nested -call test_override('unreachable', 0) - -def s:TryOne(): number - try - return 0 - catch - endtry - return 0 -enddef - -def s:TryTwo(n: number): string - try - var x = {} - catch - endtry - return 'text' -enddef - -def Test_try_catch_twice() - assert_equal('text', TryOne()->TryTwo()) -enddef - -def Test_try_catch_match() - var seq = 'a' - try - throw 'something' - catch /nothing/ - seq ..= 'x' - catch /some/ - seq ..= 'b' - catch /asdf/ - seq ..= 'x' - catch ?a\?sdf? - seq ..= 'y' - finally - seq ..= 'c' - endtry - assert_equal('abc', seq) -enddef - -def Test_try_catch_fails() - v9.CheckDefFailure(['catch'], 'E603:') - v9.CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:') - v9.CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:') - v9.CheckDefFailure(['finally'], 'E606:') - v9.CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:') - v9.CheckDefFailure(['endtry'], 'E602:') - v9.CheckDefFailure(['while 1', 'endtry'], 'E170:') - v9.CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:') - v9.CheckDefFailure(['if 1', 'endtry'], 'E171:') - v9.CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:') - v9.CheckDefFailure(['try'], 'E600:') - v9.CheckDefFailure(['try', 'echo 0'], 'E600:') - v9.CheckDefFailure(['try', 'echo 0', 'catch'], 'E600:') - v9.CheckDefFailure(['try', 'echo 0', 'catch', 'echo 1'], 'E600:') - v9.CheckDefFailure(['try', 'echo 0', 'catch', 'echo 1', 'finally'], 'E600:') - v9.CheckDefFailure(['try', 'echo 0', 'catch', 'echo 1', 'finally', 'echo 2'], 'E600:') - - # Missing :endtry inside a nested :try - var outer1 =<< trim END - try - echo 0 - catch - echo 1 - END - var outer2 =<< trim END - finally - echo 2 - endtry - END - v9.CheckDefFailure(outer1 + ['try'] + outer2, 'E600:') - v9.CheckDefFailure(outer1 + ['try', 'echo 10'] + outer2, 'E600:') - v9.CheckDefFailure(outer1 + ['try', 'echo 10', 'catch'] + outer2, 'E600:') - v9.CheckDefFailure(outer1 + ['try', 'echo 10', 'catch', 'echo 11'] + outer2, 'E600:') - v9.CheckDefFailure(outer1 + ['try', 'echo 10', 'catch', 'echo 11', 'finally'] + outer2, 'E607:') - v9.CheckDefFailure(outer1 + ['try', 'echo 10', 'catch', 'echo 11', 'finally', 'echo 12'] + outer2, 'E607:') - - v9.CheckDefFailure(['throw'], 'E1143:') - v9.CheckDefFailure(['throw xxx'], 'E1001:') -enddef - -def Try_catch_skipped() - var l = [] - try - finally - endtry - - if 1 - else - try - endtry - endif -enddef - -" The skipped try/endtry was updating the wrong instruction. -def Test_try_catch_skipped() - var instr = execute('disassemble Try_catch_skipped') - assert_match("NEWLIST size 0\n", instr) -enddef - -def Test_throw_line_number() - def Func() - eval 1 + 1 - eval 2 + 2 - throw 'exception' - enddef - def Func2() - eval 1 + 1 - eval 2 + 2 - eval 3 + 3 - throw 'exception' - enddef - try - Func() - catch /exception/ - try - Func2() - catch /exception/ - assert_match('line 4', v:throwpoint) - endtry - assert_match('line 3', v:throwpoint) - endtry - assert_match('', v:throwpoint) -enddef - - -def Test_throw_vimscript() - # only checks line continuation - var lines =<< trim END - vim9script - try - throw 'one' - .. 'two' - catch - assert_equal('onetwo', v:exception) - endtry - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - @r = '' - def Func() - throw @r - enddef - var result = '' - try - Func() - catch /E1129:/ - result = 'caught' - endtry - assert_equal('caught', result) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_error_in_nested_function() - # an error in a nested :function aborts executing in the calling :def function - var lines =<< trim END - vim9script - def Func() - Error() - g:test_var = 1 - enddef - func Error() abort - eval [][0] - endfunc - Func() - END - g:test_var = 0 - v9.CheckScriptFailure(lines, 'E684:') - assert_equal(0, g:test_var) -enddef - -def Test_abort_after_error() - var lines =<< trim END - vim9script - while true - echo notfound - endwhile - g:gotthere = true - END - g:gotthere = false - v9.CheckScriptFailure(lines, 'E121:') - assert_false(g:gotthere) - unlet g:gotthere -enddef - -def Test_cexpr_vimscript() - CheckFeature quickfix - # only checks line continuation - set errorformat=File\ %f\ line\ %l - var lines =<< trim END - vim9script - cexpr 'File' - .. ' someFile' .. - ' line 19' - assert_equal(19, getqflist()[0].lnum) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - def CexprFail() - au QuickfixCmdPre * echo g:doesnotexist - cexpr 'File otherFile line 99' - g:didContinue = 'yes' - enddef - CexprFail() - g:didContinue = 'also' - END - g:didContinue = 'no' - v9.CheckScriptFailure(lines, 'E121: Undefined variable: g:doesnotexist') - assert_equal('no', g:didContinue) - au! QuickfixCmdPre - - lines =<< trim END - vim9script - def CexprFail() - cexpr g:aNumber - g:didContinue = 'yes' - enddef - CexprFail() - g:didContinue = 'also' - END - g:aNumber = 123 - g:didContinue = 'no' - v9.CheckScriptFailure(lines, 'E777: String or List expected') - assert_equal('no', g:didContinue) - unlet g:didContinue - - set errorformat& -enddef - -def Test_statusline_syntax() - # legacy syntax is used for 'statusline' - var lines =<< trim END - vim9script - func g:Status() - return '%{"x" is# "x"}' - endfunc - set laststatus=2 statusline=%!Status() - redrawstatus - set laststatus statusline= - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_list_vimscript() - # checks line continuation and comments - var lines =<< trim END - vim9script - var mylist = [ - 'one', - # comment - 'two', # empty line follows - - 'three', - ] - assert_equal(['one', 'two', 'three'], mylist) - END - v9.CheckScriptSuccess(lines) - - # check all lines from heredoc are kept - lines =<< trim END - # comment 1 - two - # comment 3 - - five - # comment 6 - END - assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines) - - lines =<< trim END - [{ - a: 0}]->string()->assert_equal("[{'a': 0}]") - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -if has('channel') - let someJob = test_null_job() - - def FuncWithError() - echomsg g:someJob - enddef - - func Test_convert_emsg_to_exception() - try - call FuncWithError() - catch - call assert_match('Vim:E908:', v:exception) - endtry - endfunc -endif - -def Test_vim9script_mix() - var lines =<< trim END - if has(g:feature) - " legacy script - let g:legacy = 1 - finish - endif - vim9script - g:legacy = 0 - END - g:feature = 'eval' - g:legacy = -1 - v9.CheckScriptSuccess(lines) - assert_equal(1, g:legacy) - - g:feature = 'noteval' - g:legacy = -1 - v9.CheckScriptSuccess(lines) - assert_equal(0, g:legacy) -enddef - -def Test_vim9script_fails() - v9.CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') - v9.CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') - - v9.CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:') - v9.CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:') - - assert_fails('vim9script', 'E1038:') - v9.CheckDefFailure(['vim9script'], 'E1038:') - - # no error when skipping - if has('nothing') - vim9script - endif -enddef - -def Test_script_var_shadows_function() - var lines =<< trim END - vim9script - def Func(): number - return 123 - enddef - var Func = 1 - END - v9.CheckScriptFailure(lines, 'E1041:', 5) -enddef - -def Test_function_shadows_script_var() - var lines =<< trim END - vim9script - var Func = 1 - def Func(): number - return 123 - enddef - END - v9.CheckScriptFailure(lines, 'E1041:', 3) -enddef - -def Test_script_var_shadows_command() - var lines =<< trim END - var undo = 1 - undo = 2 - assert_equal(2, undo) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var undo = 1 - undo - END - v9.CheckDefAndScriptFailure(lines, 'E1207:', 2) -enddef - -def Test_vim9script_call_wrong_type() - var lines =<< trim END - vim9script - var Time = 'localtime' - Time() - END - v9.CheckScriptFailure(lines, 'E1085:') -enddef - -def Test_vim9script_reload_delfunc() - var first_lines =<< trim END - vim9script - def FuncYes(): string - return 'yes' - enddef - END - var withno_lines =<< trim END - def FuncNo(): string - return 'no' - enddef - def g:DoCheck(no_exists: bool) - assert_equal('yes', FuncYes()) - assert_equal('no', FuncNo()) - enddef - END - var nono_lines =<< trim END - def g:DoCheck(no_exists: bool) - assert_equal('yes', FuncYes()) - assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck') - enddef - END - - # FuncNo() is defined - writefile(first_lines + withno_lines, 'Xreloaded.vim', 'D') - source Xreloaded.vim - g:DoCheck(true) - - # FuncNo() is not redefined - writefile(first_lines + nono_lines, 'Xreloaded.vim') - source Xreloaded.vim - g:DoCheck(false) - - # FuncNo() is back - writefile(first_lines + withno_lines, 'Xreloaded.vim') - source Xreloaded.vim - g:DoCheck(false) -enddef - -def Test_vim9script_reload_lambda_def_func() - CheckFeature timers - - var lines =<< trim END - vim9script - - def F() - g:call_result += 1 - enddef - - augroup Xtest933 - au! - au CmdlineLeave : timer_start(0, (_) => F()) - augroup END - END - - g:call_result = 0 - writefile(lines, 'Xtest933.vim', 'D') - source Xtest933.vim - - # Simulate the CmdlineLeave event that fires before the second :so - doautocmd CmdlineLeave : - - # Re-source: F is redefined; without the fix this causes E933 when timer fires - source Xtest933.vim - - # Allow the 0ms timer to fire - sleep 10m - - assert_equal(1, g:call_result) - - augroup Xtest933 | au! | augroup END - unlet! g:call_result -enddef - -def Test_vim9script_reload_delvar() - # write the script with a script-local variable - var lines =<< trim END - vim9script - var name = 'string' - END - writefile(lines, 'XreloadVar.vim', 'D') - source XreloadVar.vim - - # now write the script using the same variable locally - works - lines =<< trim END - vim9script - def Func() - var name = 'string' - enddef - END - writefile(lines, 'XreloadVar.vim') - source XreloadVar.vim -enddef - -def Test_func_redefine_error() - var lines = [ - 'vim9script', - 'def Func()', - ' eval [][0]', - 'enddef', - 'Func()', - ] - writefile(lines, 'Xtestscript.vim', 'D') - - for count in range(3) - try - source Xtestscript.vim - catch /E684/ - # function name should contain <SNR> every time - assert_match('E684: List index out of range', v:exception) - assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint) - endtry - endfor -enddef - -def Test_func_redefine_fails() - var lines =<< trim END - vim9script - def Func() - echo 'one' - enddef - def Func() - echo 'two' - enddef - END - v9.CheckScriptFailure(lines, 'E1073:') - - lines =<< trim END - vim9script - def Foo(): string - return 'foo' - enddef - def Func() - var Foo = {-> 'lambda'} - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1073:') -enddef - -def Test_lambda_split() - # this was using freed memory, because of the split expression - var lines =<< trim END - vim9script - try - 0 - 0->(0 - ->a.0( - ->u - END - v9.CheckScriptFailure(lines, 'E1050:') -enddef - -def Test_fixed_size_list() - # will be allocated as one piece of memory, check that changes work - var l = [1, 2, 3, 4] - l->remove(0) - l->add(5) - l->insert(99, 1) - assert_equal([2, 99, 3, 4, 5], l) -enddef - -def Test_no_insert_xit() - v9.CheckDefExecFailure(['a = 1'], 'E1100:') - v9.CheckDefExecFailure(['c = 1'], 'E1100:') - v9.CheckDefExecFailure(['i = 1'], 'E1100:') - v9.CheckDefExecFailure(['t = 1'], 'E1100:') - v9.CheckDefExecFailure(['x = 1'], 'E1100:') - - v9.CheckScriptFailure(['vim9script', 'a = 1'], 'E488:') - v9.CheckScriptFailure(['vim9script', 'a'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 'c = 1'], 'E488:') - v9.CheckScriptFailure(['vim9script', 'c'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 'i = 1'], 'E488:') - v9.CheckScriptFailure(['vim9script', 'i'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 'o'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 't'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 't = 1'], 'E1100:') - v9.CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:') -enddef - -def s:IfElse(what: number): string - var res = '' - if what == 1 - res = "one" - elseif what == 2 - res = "two" - else - res = "three" - endif - return res -enddef - -def Test_if_elseif_else() - assert_equal('one', IfElse(1)) - assert_equal('two', IfElse(2)) - assert_equal('three', IfElse(3)) -enddef - -def Test_if_elseif_else_fails() - v9.CheckDefFailure(['elseif true'], 'E582:') - v9.CheckDefFailure(['else'], 'E581:') - v9.CheckDefFailure(['endif'], 'E580:') - v9.CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:') - v9.CheckDefFailure(['if true', 'echo 1'], 'E171:') - - var lines =<< trim END - var s = '' - if s = '' - endif - END - v9.CheckDefFailure(lines, 'E488:') - - lines =<< trim END - var s = '' - if s == '' - elseif s = '' - endif - END - v9.CheckDefFailure(lines, 'E488:') - - - lines =<< trim END - if true - else - else - endif - END - v9.CheckSourceDefFailure(lines, 'E583:') - - lines =<< trim END - var a = 3 - if a == 2 - else - elseif true - else - endif - END - v9.CheckSourceDefFailure(lines, 'E584:') - - lines =<< trim END - var cond = true - if cond - echo 'true' - elseif - echo 'false' - endif - END - v9.CheckDefAndScriptFailure(lines, ['E1143:', 'E15:'], 4) -enddef - -def Test_if_else_func_using_var() - var lines =<< trim END - vim9script - - const debug = true - if debug - var mode_chars = 'something' - def Bits2Ascii() - var x = mode_chars - g:where = 'in true' - enddef - else - def Bits2Ascii() - g:where = 'in false' - enddef - endif - - Bits2Ascii() - END - v9.CheckScriptSuccess(lines) - assert_equal('in true', g:where) - unlet g:where - - lines =<< trim END - vim9script - - const debug = false - if debug - var mode_chars = 'something' - def Bits2Ascii() - g:where = 'in true' - enddef - else - def Bits2Ascii() - var x = mode_chars - g:where = 'in false' - enddef - endif - - Bits2Ascii() - END - v9.CheckScriptFailure(lines, 'E1001: Variable not found: mode_chars') -enddef - -let g:bool_true = v:true -let g:bool_false = v:false - -def Test_if_const_expr() - var res = false - if true ? true : false - res = true - endif - assert_equal(true, res) - - g:glob = 2 - if false - execute('g:glob = 3') - endif - assert_equal(2, g:glob) - if true - execute('g:glob = 3') - endif - assert_equal(3, g:glob) - - res = false - if g:bool_true ? true : false - res = true - endif - assert_equal(true, res) - - res = false - if true ? g:bool_true : false - res = true - endif - assert_equal(true, res) - - res = false - if true ? true : g:bool_false - res = true - endif - assert_equal(true, res) - - res = false - if true ? false : true - res = true - endif - assert_equal(false, res) - - res = false - if false ? false : true - res = true - endif - assert_equal(true, res) - - res = false - if false ? true : false - res = true - endif - assert_equal(false, res) - - res = false - if has('xyz') ? true : false - res = true - endif - assert_equal(false, res) - - res = false - if true && true - res = true - endif - assert_equal(true, res) - - res = false - if true && false - res = true - endif - assert_equal(false, res) - - res = false - if g:bool_true && false - res = true - endif - assert_equal(false, res) - - res = false - if true && g:bool_false - res = true - endif - assert_equal(false, res) - - res = false - if false && false - res = true - endif - assert_equal(false, res) - - res = false - if true || false - res = true - endif - assert_equal(true, res) - - res = false - if g:bool_true || false - res = true - endif - assert_equal(true, res) - - res = false - if true || g:bool_false - res = true - endif - assert_equal(true, res) - - res = false - if false || false - res = true - endif - assert_equal(false, res) - - # with constant "false" expression may be invalid so long as the syntax is OK - if false | eval 1 + 2 | endif - if false | eval burp + 234 | endif - if false | echo burp 234 'asd' | endif - if false - burp - endif - - if 0 - if 1 - echo nothing - elseif 1 - echo still nothing - endif - endif - - # expression with line breaks skipped - if false - ('aaa' - .. 'bbb' - .. 'ccc' - )->setline(1) - endif - - if 1 - # do nothing - else - var [a] = [10] - endif -enddef - -def Test_if_const_expr_fails() - v9.CheckDefFailure(['if "aaa" == "bbb'], 'E114:') - v9.CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:') - v9.CheckDefFailure(["if has('aaa'"], 'E110:') - v9.CheckDefFailure(["if has('aaa') ? true false"], 'E109:') -enddef - -def s:RunNested(i: number): number - var x: number = 0 - if i % 2 - if 1 - # comment - else - # comment - endif - x += 1 - else - x += 1000 - endif - return x -enddef - -def Test_nested_if() - assert_equal(1, RunNested(1)) - assert_equal(1000, RunNested(2)) -enddef - -def Test_execute_cmd() - # missing argument is ignored - execute - execute # comment - - new - setline(1, 'default') - execute 'setline(1, "execute-string")' - assert_equal('execute-string', getline(1)) - - execute "setline(1, 'execute-string')" - assert_equal('execute-string', getline(1)) - - var cmd1 = 'setline(1,' - var cmd2 = '"execute-var")' - execute cmd1 cmd2 # comment - assert_equal('execute-var', getline(1)) - - execute cmd1 cmd2 '|setline(1, "execute-var-string")' - assert_equal('execute-var-string', getline(1)) - - var cmd_first = 'call ' - var cmd_last = 'setline(1, "execute-var-var")' - execute cmd_first .. cmd_last - assert_equal('execute-var-var', getline(1)) - bwipe! - - var n = true - execute 'echomsg' (n ? '"true"' : '"no"') - assert_match('^true$', g:Screenline(&lines)) - - echomsg [1, 2, 3] {a: 1, b: 2} - assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', g:Screenline(&lines)) - - v9.CheckDefFailure(['execute xxx'], 'E1001:', 1) - v9.CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1) - v9.CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1) - if has('channel') - v9.CheckDefExecFailure(['execute test_null_channel()'], 'E908:', 1) - endif -enddef - -def Test_execute_cmd_vimscript() - # only checks line continuation - var lines =<< trim END - vim9script - execute 'g:someVar' - .. ' = ' .. - '28' - assert_equal(28, g:someVar) - unlet g:someVar - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_execute_finish() - # the empty lines are relevant here - var lines =<< trim END - vim9script - - var vname = "g:hello" - - if exists(vname) | finish | endif | execute vname '= "world"' - - assert_equal('world', g:hello) - - if exists(vname) | finish | endif | execute vname '= "world"' - - assert_report('should not be reached') - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_echo_cmd() - echo 'some' # comment - echon 'thing' - assert_match('^something$', g:Screenline(&lines)) - - echo "some" # comment - echon "thing" - assert_match('^something$', g:Screenline(&lines)) - - var str1 = 'some' - var str2 = 'more' - echo str1 str2 - assert_match('^some more$', g:Screenline(&lines)) - - echo "one\ntwo" - assert_match('^one$', g:Screenline(&lines - 1)) - assert_match('^two$', g:Screenline(&lines)) - - v9.CheckDefFailure(['echo "xxx"# comment'], 'E488:') - - # Test for echoing a script local function name - var lines =<< trim END - vim9script - def ScriptLocalEcho() - enddef - echo ScriptLocalEcho - END - new - setline(1, lines) - assert_match('<SNR>\d\+_ScriptLocalEcho', execute('source')->split("\n")[0]) - bw! -enddef - -def Test_echomsg_cmd() - echomsg 'some' 'more' # comment - assert_match('^some more$', g:Screenline(&lines)) - echo 'clear' - :1messages - assert_match('^some more$', g:Screenline(&lines)) - - v9.CheckDefFailure(['echomsg "xxx"# comment'], 'E488:') -enddef - -def Test_echomsg_cmd_vimscript() - # only checks line continuation - var lines =<< trim END - vim9script - echomsg 'here' - .. ' is ' .. - 'a message' - assert_match('^here is a message$', g:Screenline(&lines)) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_echoerr_cmd() - var local = 'local' - try - echoerr 'something' local 'wrong' # comment - catch - assert_match('something local wrong', v:exception) - endtry -enddef - -def Test_echoerr_cmd_vimscript() - # only checks line continuation - var lines =<< trim END - vim9script - try - echoerr 'this' - .. ' is ' .. - 'wrong' - catch - assert_match('this is wrong', v:exception) - endtry - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_echoconsole_cmd() - var local = 'local' - echoconsole 'something' local # comment - # output goes anywhere -enddef - -def Test_echowindow_cmd() - var local = 'local' - echowindow 'something' local # comment - - # with modifier - unsilent echowin 'loud' - - # output goes in message window - popup_clear() - - # Invalid range - var lines =<< trim END - def Foo() - :$echowindow "foo" - enddef - defcompile - END - v9.CheckDefAndScriptFailure(lines, 'E16: Invalid range') -enddef - -def Test_for_outside_of_function() - var lines =<< trim END - vim9script - new - for var in range(0, 3) - append(line('$'), var) - endfor - assert_equal(['', '0', '1', '2', '3'], getline(1, '$')) - bwipe! - - var result = '' - for i in [1, 2, 3] - var loop = ' loop ' .. i - result ..= loop - endfor - assert_equal(' loop 1 loop 2 loop 3', result) - END - writefile(lines, 'Xvim9for.vim', 'D') - source Xvim9for.vim -enddef - -def Test_for_skipped_block() - # test skipped blocks at outside of function - var lines =<< trim END - var result = [] - if true - for n in [1, 2] - result += [n] - endfor - else - for n in [3, 4] - result += [n] - endfor - endif - assert_equal([1, 2], result) - - result = [] - if false - for n in [1, 2] - result += [n] - endfor - else - for n in [3, 4] - result += [n] - endfor - endif - assert_equal([3, 4], result) - END - v9.CheckDefAndScriptSuccess(lines) - - # test skipped blocks at inside of function - lines =<< trim END - def DefTrue() - var result = [] - if true - for n in [1, 2] - result += [n] - endfor - else - for n in [3, 4] - result += [n] - endfor - endif - assert_equal([1, 2], result) - enddef - DefTrue() - - def DefFalse() - var result = [] - if false - for n in [1, 2] - result += [n] - endfor - else - for n in [3, 4] - result += [n] - endfor - endif - assert_equal([3, 4], result) - enddef - DefFalse() - - def BuildDiagrams() - var diagrams: list<any> - if false - var max = 0 - for v in diagrams - var l = 3 - if max < l | max = l | endif - v->add(l) - endfor - endif - enddef - BuildDiagrams() - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_skipped_redir() - var lines =<< trim END - def Tredir() - if 0 - redir => l[0] - redir END - endif - enddef - defcompile - END - v9.CheckScriptSuccess(lines) - delfunc g:Tredir - - lines =<< trim END - def Tredir() - if 0 - redir => l[0] - endif - echo 'executed' - if 0 - redir END - endif - enddef - defcompile - END - v9.CheckScriptSuccess(lines) - delfunc g:Tredir - - lines =<< trim END - def Tredir() - var l = [''] - if 1 - redir => l[0] - endif - echo 'executed' - if 0 - redir END - else - redir END - endif - enddef - defcompile - END - v9.CheckScriptSuccess(lines) - delfunc g:Tredir - - lines =<< trim END - let doit = 1 - def Tredir() - var l = [''] - if g:doit - redir => l[0] - endif - echo 'executed' - if g:doit - redir END - endif - enddef - defcompile - END - v9.CheckScriptSuccess(lines) - delfunc g:Tredir -enddef - -def Test_for_loop() - var lines =<< trim END - var result = '' - for cnt in range(7) - if cnt == 4 - break - endif - if cnt == 2 - continue - endif - result ..= cnt .. '_' - endfor - assert_equal('0_1_3_', result) - - var concat = '' - for str in eval('["one", "two"]') - concat ..= str - endfor - assert_equal('onetwo', concat) - - var total = 0 - for nr in - [1, 2, 3] - total += nr - endfor - assert_equal(6, total) - - total = 0 - for nr - in [1, 2, 3] - total += nr - endfor - assert_equal(6, total) - - total = 0 - for nr - in - [1, 2, 3] - total += nr - endfor - assert_equal(6, total) - - # with type - total = 0 - for n: number in [1, 2, 3] - total += n - endfor - assert_equal(6, total) - - total = 0 - for b in 0z010203 - total += b - endfor - assert_equal(6, total) - - var chars = '' - for s: string in 'foobar' - chars ..= s - endfor - assert_equal('foobar', chars) - - chars = '' - for x: string in {a: 'a', b: 'b'}->values() - chars ..= x - endfor - assert_equal('ab', chars) - - # unpack with type - var res = '' - for [n: number, s: string] in [[1, 'a'], [2, 'b']] - res ..= n .. s - endfor - assert_equal('1a2b', res) - - # unpack with one var - var reslist = [] - for [x] in [['aaa'], ['bbb']] - reslist->add(x) - endfor - assert_equal(['aaa', 'bbb'], reslist) - - # loop over string - res = '' - for c in 'aéc̀d' - res ..= c .. '-' - endfor - assert_equal('a-é-c̀-d-', res) - - res = '' - for c in '' - res ..= c .. '-' - endfor - assert_equal('', res) - - res = '' - for c in test_null_string() - res ..= c .. '-' - endfor - assert_equal('', res) - - total = 0 - for c in null_list - total += 1 - endfor - assert_equal(0, total) - - for c in null_blob - total += 1 - endfor - assert_equal(0, total) - - var foo: list<dict<any>> = [ - {a: 'Cat'} - ] - for dd in foo - dd.counter = 12 - endfor - assert_equal([{a: 'Cat', counter: 12}], foo) - - reslist = [] - for _ in range(3) - reslist->add('x') - endfor - assert_equal(['x', 'x', 'x'], reslist) - - # Test for trying to use the loop variable "_" inside the loop - for _ in "a" - assert_fails('echo _', 'E1181: Cannot use an underscore here') - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - for i : number : [1, 2] - echo i - endfor - END - v9.CheckSourceDefAndScriptFailure(lines, 'E1059: No white space allowed before colon: : [1, 2]', 1) -enddef - -def Test_for_loop_list_of_lists() - # loop variable is final, not const - var lines =<< trim END - # Filter out all odd numbers in each sublist - var list: list<list<number>> = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]] - for i in list - filter(i, (_, n: number): bool => n % 2 == 0) - endfor - - assert_equal([[], [2], [2], [2, 4]], list) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_for_loop_with_closure() - # using the loop variable in a closure results in the last used value - var lines =<< trim END - var flist: list<func> - for i in range(5) - flist[i] = () => i - endfor - for i in range(5) - assert_equal(4, flist[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - # also works when the loop variable is used only once halfway the loops - lines =<< trim END - var Clo: func - for i in range(5) - if i == 3 - Clo = () => i - endif - endfor - assert_equal(4, Clo()) - END - v9.CheckDefAndScriptSuccess(lines) - - # using a local variable set to the loop variable in a closure results in the - # value at that moment - lines =<< trim END - var flist: list<func> - for i in range(5) - var inloop = i - flist[i] = () => inloop - endfor - for i in range(5) - assert_equal(i, flist[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - # also with an extra block level - lines =<< trim END - var flist: list<func> - for i in range(5) - { - var inloop = i - flist[i] = () => inloop - } - endfor - for i in range(5) - assert_equal(i, flist[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - # and declaration in higher block - lines =<< trim END - var flist: list<func> - for i in range(5) - var inloop = i - { - flist[i] = () => inloop - } - endfor - for i in range(5) - assert_equal(i, flist[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var flist: list<func> - for i in range(5) - var inloop = i - flist[i] = () => { - return inloop - } - endfor - for i in range(5) - assert_equal(i, flist[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - # Also works for a nested loop - lines =<< trim END - var flist: list<func> - var n = 0 - for i in range(3) - var ii = i - for a in ['a', 'b', 'c'] - var aa = a - flist[n] = () => ii .. aa - ++n - endfor - endfor - - n = 0 - for i in range(3) - for a in ['a', 'b', 'c'] - assert_equal(i .. a, flist[n]()) - ++n - endfor - endfor - END - v9.CheckDefAndScriptSuccess(lines) - - # using two loop variables - lines =<< trim END - var lv_list: list<func> - var copy_list: list<func> - for [idx, c] in items('word') - var lidx = idx - var lc = c - lv_list[idx] = () => { - return idx .. c - } - copy_list[idx] = () => { - return lidx .. lc - } - endfor - for [i, c] in items('word') - assert_equal(3 .. 'd', lv_list[i]()) - assert_equal(i .. c, copy_list[i]()) - endfor - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_define_global_closure_in_loops() - var lines =<< trim END - vim9script - - def Func() - for i in range(3) - var ii = i - for a in ['a', 'b', 'c'] - var aa = a - if ii == 0 && aa == 'a' - def g:Global_0a(): string - return ii .. aa - enddef - endif - if ii == 1 && aa == 'b' - def g:Global_1b(): string - return ii .. aa - enddef - endif - if ii == 2 && aa == 'c' - def g:Global_2c(): string - return ii .. aa - enddef - endif - endfor - endfor - enddef - Func() - END - v9.CheckScriptSuccess(lines) - assert_equal("0a", g:Global_0a()) - assert_equal("1b", g:Global_1b()) - assert_equal("2c", g:Global_2c()) - - delfunc g:Global_0a - delfunc g:Global_1b - delfunc g:Global_2c -enddef - -" Test for using a closure in a for loop after another for/while loop -def Test_for_loop_with_closure_after_another_loop() - var lines =<< trim END - vim9script - def Fn() - # first loop with a local variable - for i in 'a' - var v1 = 0 - endfor - var idx = 1 - while idx > 0 - idx -= 1 - endwhile - var results = [] - var s = 'abc' - # second loop with a local variable and a funcref - for j in range(2) - var k = 0 - results->add(s) - g:FuncRefs = () => j - endfor - assert_equal(['abc', 'abc'], results) - enddef - Fn() - END - v9.CheckScriptSuccess(lines) - unlet g:FuncRefs -enddef - -def Test_for_loop_fails() - v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:']) - v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:']) - v9.CheckDefAndScriptFailure(['for x in'], ['E1097:', 'E15:']) - v9.CheckDefAndScriptFailure(['for # in range(5)'], 'E690:') - v9.CheckDefAndScriptFailure(['for i In range(5)'], 'E690:') - v9.CheckDefAndScriptFailure(['var x = 5', 'for x in range(5)', 'endfor'], ['E1017:', 'E1041:']) - v9.CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3) - v9.CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:') - delfunc! g:Func - v9.CheckDefFailure(['for i in xxx'], 'E1001:') - v9.CheckDefFailure(['endfor'], 'E588:') - v9.CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:') - - # wrong type detected at compile time - v9.CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported') - - # wrong type detected at runtime - g:adict = {a: 1} - v9.CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported') - unlet g:adict - - var lines =<< trim END - var d: list<dict<any>> = [{a: 0}] - for e in d - e = {a: 0, b: ''} - endfor - END - v9.CheckDefAndScriptFailure(lines, ['E1018:', 'E46:'], 3) - - lines =<< trim END - for nr: number in ['foo'] - endfor - END - v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1) - - lines =<< trim END - for n : number in [1, 2] - echo n - endfor - END - v9.CheckDefAndScriptFailure(lines, 'E1059:', 1) - - lines =<< trim END - var d: dict<number> = {a: 1, b: 2} - for [k: job, v: job] in d->items() - echo k v - endfor - END - v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 1: type mismatch, expected job but got string', 'E1012: Type mismatch; expected job but got string'], 2) - - lines =<< trim END - var i = 0 - for i in [1, 2, 3] - echo i - endfor - END - v9.CheckDefExecAndScriptFailure(lines, ['E1017:', 'E1041:']) - - lines =<< trim END - var l = [0] - for l[0] in [1, 2, 3] - echo l[0] - endfor - END - v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:']) - - lines =<< trim END - var d = {x: 0} - for d.x in [1, 2, 3] - echo d.x - endfor - END - v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:']) - - lines =<< trim END - var l: list<dict<any>> = [{a: 1, b: 'x'}] - for item: dict<number> in l - echo item - endfor - END - v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<number> but got dict<any>') - - lines =<< trim END - var l: list<dict<any>> = [{n: 1}] - for item: dict<number> in l - var d = {s: ''} - d->extend(item) - endfor - END - v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<string> but got dict<number>') - - lines =<< trim END - for a in range(3) - while a > 3 - for b in range(2) - while b < 0 - for c in range(5) - while c > 6 - while c < 0 - for d in range(1) - for e in range(3) - while e > 3 - endwhile - endfor - endfor - endwhile - endwhile - endfor - endwhile - endfor - endwhile - endfor - END - v9.CheckDefSuccess(lines) - - v9.CheckDefFailure(['for x in range(3)'] + lines + ['endfor'], 'E1306:') - - # Test for too many for loops - lines =<< trim END - vim9script - def Foo() - for a in range(1) - for b in range(1) - for c in range(1) - for d in range(1) - for e in range(1) - for f in range(1) - for g in range(1) - for h in range(1) - for i in range(1) - for j in range(1) - for k in range(1) - endfor - endfor - endfor - endfor - endfor - endfor - endfor - endfor - endfor - endfor - endfor - enddef - defcompile - END - v9.CheckSourceFailure(lines, 'E1306: Loop nesting too deep', 11) -enddef - -def Test_for_loop_script_var() - # cannot use s:var in a :def function - v9.CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1254:') - - # can use s:var in Vim9 script, with or without s: - var lines =<< trim END - vim9script - var total = 0 - for s:var in [1, 2, 3] - total += s:var - endfor - assert_equal(6, total) - - total = 0 - for var in [1, 2, 3] - total += var - endfor - assert_equal(6, total) - END -enddef - -def Test_for_loop_unpack() - var lines =<< trim END - var result = [] - for [v1, v2] in [[1, 2], [3, 4]] - result->add(v1) - result->add(v2) - endfor - assert_equal([1, 2, 3, 4], result) - - result = [] - for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]] - result->add(v1) - result->add(v2) - result->add(v3) - endfor - assert_equal([1, 2, [], 3, 4, [5, 6]], result) - - result = [] - for [&ts, &sw] in [[1, 2], [3, 4]] - result->add(&ts) - result->add(&sw) - endfor - assert_equal([1, 2, 3, 4], result) - - var slist: list<string> - for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']] - slist->add($LOOPVAR) - slist->add(@r) - slist->add(v:errmsg) - endfor - assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist) - - slist = [] - for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']] - slist->add(g:globalvar) - slist->add(b:bufvar) - slist->add(w:winvar) - slist->add(t:tabvar) - endfor - assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist) - unlet! g:globalvar b:bufvar w:winvar t:tabvar - - var res = [] - for [_, n, _] in [[1, 2, 3], [4, 5, 6]] - res->add(n) - endfor - assert_equal([2, 5], res) - - var text: list<string> = ["hello there", "goodbye now"] - var splitted = '' - for [first; next] in mapnew(text, (i, v) => split(v)) - splitted ..= string(first) .. string(next) .. '/' - endfor - assert_equal("'hello'['there']/'goodbye'['now']/", splitted) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - for [v1, v2] in [[1, 2, 3], [3, 4]] - echo v1 v2 - endfor - END - v9.CheckDefExecFailure(lines, 'E710:', 1) - - lines =<< trim END - for [v1, v2] in [[1], [3, 4]] - echo v1 v2 - endfor - END - v9.CheckDefExecFailure(lines, 'E711:', 1) - - lines =<< trim END - for [v1, v1] in [[1, 2], [3, 4]] - echo v1 - endfor - END - v9.CheckDefExecFailure(lines, 'E1017:', 1) - - lines =<< trim END - for [a, b] in g:listlist - echo a - endfor - END - g:listlist = [1, 2, 3] - v9.CheckDefExecFailure(lines, 'E1140:', 1) -enddef - -def Test_for_loop_with_try_continue() - var lines =<< trim END - var looped = 0 - var cleanup = 0 - for i in range(3) - looped += 1 - try - eval [][0] - catch - continue - finally - cleanup += 1 - endtry - endfor - assert_equal(3, looped) - assert_equal(3, cleanup) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_while_skipped_block() - # test skipped blocks at outside of function - var lines =<< trim END - var result = [] - var n = 0 - if true - n = 1 - while n < 3 - result += [n] - n += 1 - endwhile - else - n = 3 - while n < 5 - result += [n] - n += 1 - endwhile - endif - assert_equal([1, 2], result) - - result = [] - if false - n = 1 - while n < 3 - result += [n] - n += 1 - endwhile - else - n = 3 - while n < 5 - result += [n] - n += 1 - endwhile - endif - assert_equal([3, 4], result) - END - v9.CheckDefAndScriptSuccess(lines) - - # test skipped blocks at inside of function - lines =<< trim END - def DefTrue() - var result = [] - var n = 0 - if true - n = 1 - while n < 3 - result += [n] - n += 1 - endwhile - else - n = 3 - while n < 5 - result += [n] - n += 1 - endwhile - endif - assert_equal([1, 2], result) - enddef - DefTrue() - - def DefFalse() - var result = [] - var n = 0 - if false - n = 1 - while n < 3 - result += [n] - n += 1 - endwhile - else - n = 3 - while n < 5 - result += [n] - n += 1 - endwhile - endif - assert_equal([3, 4], result) - enddef - DefFalse() - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_while_loop() - var result = '' - var cnt = 0 - while cnt < 555 - if cnt == 3 - break - endif - cnt += 1 - if cnt == 2 - continue - endif - result ..= cnt .. '_' - endwhile - assert_equal('1_3_', result) - - var s = '' - while s == 'x' # {comment} - endwhile -enddef - -def Test_while_loop_in_script() - var lines =<< trim END - vim9script - var result = '' - var cnt = 0 - while cnt < 3 - var s = 'v' .. cnt - result ..= s - cnt += 1 - endwhile - assert_equal('v0v1v2', result) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_while_loop_fails() - v9.CheckDefFailure(['while xxx'], 'E1001:') - v9.CheckDefFailure(['endwhile'], 'E588:') - v9.CheckDefFailure(['continue'], 'E586:') - v9.CheckDefFailure(['if true', 'continue'], 'E586:') - v9.CheckDefFailure(['break'], 'E587:') - v9.CheckDefFailure(['if true', 'break'], 'E587:') - v9.CheckDefFailure(['while 1', 'echo 3'], 'E170:') - - var lines =<< trim END - var s = '' - while s = '' - endwhile - END - v9.CheckDefFailure(lines, 'E488:') -enddef - -def Test_interrupt_loop() - var caught = false - var x = 0 - try - while 1 - x += 1 - if x == 100 - feedkeys("\<C-C>", 'Lt') - endif - endwhile - catch - caught = true - assert_equal(100, x) - endtry - assert_true(caught, 'should have caught an exception') - # consume the CTRL-C - getchar(0) -enddef - -def Test_automatic_line_continuation() - var mylist = [ - 'one', - 'two', - 'three', - ] # comment - assert_equal(['one', 'two', 'three'], mylist) - - var mydict = { - ['one']: 1, - ['two']: 2, - ['three']: - 3, - } # comment - assert_equal({one: 1, two: 2, three: 3}, mydict) - mydict = { - one: 1, # comment - two: # comment - 2, # comment - three: 3 # comment - } - assert_equal({one: 1, two: 2, three: 3}, mydict) - mydict = { - one: 1, - two: - 2, - three: 3 - } - assert_equal({one: 1, two: 2, three: 3}, mydict) - - assert_equal( - ['one', 'two', 'three'], - split('one two three') - ) -enddef - -def Test_vim9_comment() - v9.CheckScriptSuccess([ - 'vim9script', - '# something', - '#something', - '#{{something', - ]) - v9.CheckScriptFailure([ - 'vim9script', - '#{something', - ], 'E1170:') - - split Xv9cfile - v9.CheckScriptSuccess([ - 'vim9script', - 'edit #something', - ]) - v9.CheckScriptSuccess([ - 'vim9script', - 'edit #{something', - ]) - close - - v9.CheckScriptFailure([ - 'vim9script', - ':# something', - ], 'E488:') - v9.CheckScriptFailure([ - '# something', - ], 'E488:') - v9.CheckScriptFailure([ - ':# something', - ], 'E488:') - - { # block start - } # block end - v9.CheckDefFailure([ - '{# comment', - ], 'E488:') - v9.CheckDefFailure([ - '{', - '}# comment', - ], 'E488:') - - echo "yes" # comment - v9.CheckDefFailure([ - 'echo "yes"# comment', - ], 'E488:') - v9.CheckScriptSuccess([ - 'vim9script', - 'echo "yes" # something', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'echo "yes"# something', - ], 'E121:') - v9.CheckScriptFailure([ - 'vim9script', - 'echo# something', - ], 'E1144:') - v9.CheckScriptFailure([ - 'echo "yes" # something', - ], 'E121:') - - exe "echo" # comment - v9.CheckDefFailure([ - 'exe "echo"# comment', - ], 'E488:') - v9.CheckScriptSuccess([ - 'vim9script', - 'exe "echo" # something', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'exe "echo"# something', - ], 'E121:') - v9.CheckScriptFailure([ - 'vim9script', - 'exe# something', - ], 'E1144:') - v9.CheckScriptFailure([ - 'exe "echo" # something', - ], 'E121:') - - v9.CheckDefFailure([ - 'try# comment', - ' echo "yes"', - 'catch', - 'endtry', - ], 'E1144:') - v9.CheckScriptFailure([ - 'vim9script', - 'try# comment', - 'echo "yes"', - ], 'E1144:') - v9.CheckDefFailure([ - 'try', - ' throw#comment', - 'catch', - 'endtry', - ], 'E1144:') - v9.CheckDefFailure([ - 'try', - ' throw "yes"#comment', - 'catch', - 'endtry', - ], 'E488:') - v9.CheckDefFailure([ - 'try', - ' echo "yes"', - 'catch# comment', - 'endtry', - ], 'E1144:') - v9.CheckScriptFailure([ - 'vim9script', - 'try', - ' echo "yes"', - 'catch# comment', - 'endtry', - ], 'E1144:') - v9.CheckDefFailure([ - 'try', - ' echo "yes"', - 'catch /pat/# comment', - 'endtry', - ], 'E488:') - v9.CheckDefFailure([ - 'try', - 'echo "yes"', - 'catch', - 'endtry# comment', - ], 'E1144:') - v9.CheckScriptFailure([ - 'vim9script', - 'try', - ' echo "yes"', - 'catch', - 'endtry# comment', - ], 'E1144:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'hi # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'hi# comment', - ], 'E1144:') - v9.CheckScriptSuccess([ - 'vim9script', - 'hi Search # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'hi Search# comment', - ], 'E416:') - v9.CheckScriptSuccess([ - 'vim9script', - 'hi link This Search # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'hi link This That# comment', - ], 'E413:') - v9.CheckScriptSuccess([ - 'vim9script', - 'hi clear This # comment', - 'hi clear # comment', - ]) - # not tested, because it doesn't give an error but a warning: - # hi clear This# comment', - v9.CheckScriptFailure([ - 'vim9script', - 'hi clear# comment', - ], 'E416:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'hi Group term=bold', - 'match Group /todo/ # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'hi Group term=bold', - 'match Group /todo/# comment', - ], 'E488:') - v9.CheckScriptSuccess([ - 'vim9script', - 'match # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'match# comment', - ], 'E1144:') - v9.CheckScriptSuccess([ - 'vim9script', - 'match none # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'match none# comment', - ], 'E475:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'menutrans clear # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'menutrans clear# comment text', - ], 'E474:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax clear # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax clear# comment text', - ], 'E28:') - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax keyword Word some', - 'syntax clear Word # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax keyword Word some', - 'syntax clear Word# comment text', - ], 'E28:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax list # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax list# comment text', - ], 'E28:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax match Word /pat/ oneline # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax match Word /pat/ oneline# comment', - ], 'E475:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax keyword Word word # comm[ent', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax keyword Word word# comm[ent', - ], 'E789:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax match Word /pat/ # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax match Word /pat/# comment', - ], 'E402:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax match Word /pat/ contains=Something # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax match Word /pat/ contains=Something# comment', - ], 'E475:') - v9.CheckScriptFailure([ - 'vim9script', - 'syntax match Word /pat/ contains= # comment', - ], 'E406:') - v9.CheckScriptFailure([ - 'vim9script', - 'syntax match Word /pat/ contains=# comment', - ], 'E475:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax region Word start=/pat/ end=/pat/ # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax region Word start=/pat/ end=/pat/# comment', - ], 'E402:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax sync # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax sync# comment', - ], 'E404:') - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax sync ccomment # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax sync ccomment# comment', - ], 'E404:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'syntax cluster Some contains=Word # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'syntax cluster Some contains=Word# comment', - ], 'E475:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'command Echo echo # comment', - 'command Echo # comment', - 'delcommand Echo', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'command Echo echo# comment', - 'Echo', - ], 'E1144:') - delcommand Echo - - var curdir = getcwd() - v9.CheckScriptSuccess([ - 'command Echo cd " comment', - 'Echo', - 'delcommand Echo', - ]) - v9.CheckScriptSuccess([ - 'vim9script', - 'command Echo cd # comment', - 'Echo', - 'delcommand Echo', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'command Echo cd " comment', - 'Echo', - ], 'E344:') - delcommand Echo - chdir(curdir) - - v9.CheckScriptFailure([ - 'vim9script', - 'command Echo# comment', - ], 'E182:') - v9.CheckScriptFailure([ - 'vim9script', - 'command Echo echo', - 'command Echo# comment', - ], 'E182:') - delcommand Echo - - v9.CheckScriptSuccess([ - 'vim9script', - 'function # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'function " comment', - ], 'E129:') - v9.CheckScriptFailure([ - 'vim9script', - 'function# comment', - ], 'E1144:') - v9.CheckScriptSuccess([ - 'vim9script', - 'import "./util/vim9.vim" as v9', - 'function v9.CheckScriptSuccess # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'import "./util/vim9.vim" as v9', - 'function v9.CheckScriptSuccess# comment', - ], 'E1048: Item not found in script: CheckScriptSuccess#') - - v9.CheckScriptSuccess([ - 'vim9script', - 'func g:DeleteMeA()', - 'endfunc', - 'delfunction g:DeleteMeA # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'func g:DeleteMeB()', - 'endfunc', - 'delfunction g:DeleteMeB# comment', - ], 'E488:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'call execute("ls") # comment', - ]) - v9.CheckScriptFailure([ - 'vim9script', - 'call execute("ls")# comment', - ], 'E488:') - - v9.CheckScriptFailure([ - 'def Test() " comment', - 'enddef', - ], 'E488:') - v9.CheckScriptFailure([ - 'vim9script', - 'def Test() " comment', - 'enddef', - ], 'E488:') - - v9.CheckScriptSuccess([ - 'func Test() " comment', - 'endfunc', - 'delfunc Test', - ]) - v9.CheckScriptSuccess([ - 'vim9script', - 'func Test() " comment', - 'endfunc', - ]) - - v9.CheckScriptSuccess([ - 'def Test() # comment', - 'enddef', - ]) - v9.CheckScriptFailure([ - 'func Test() # comment', - 'endfunc', - ], 'E488:') - - var lines =<< trim END - vim9script - syn region Text - \ start='foo' - #\ comment - \ end='bar' - syn region Text start='foo' - #\ comment - \ end='bar' - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - syn region Text - \ start='foo' - "\ comment - \ end='bar' - END - v9.CheckScriptFailure(lines, 'E399:') -enddef - -def Test_vim9_comment_gui() - CheckCanRunGui - - v9.CheckScriptFailure([ - 'vim9script', - 'gui#comment' - ], 'E1144:') - v9.CheckScriptFailure([ - 'vim9script', - 'gui -f#comment' - ], 'E194:') -enddef - -def Test_vim9_comment_not_compiled() - au TabEnter *.vim g:entered = 1 - au TabEnter *.x g:entered = 2 - - edit test.vim - doautocmd TabEnter #comment - assert_equal(1, g:entered) - - doautocmd TabEnter f.x - assert_equal(2, g:entered) - - g:entered = 0 - doautocmd TabEnter f.x #comment - assert_equal(2, g:entered) - - assert_fails('doautocmd Syntax#comment', 'E216:') - - au! TabEnter - unlet g:entered - - v9.CheckScriptSuccess([ - 'vim9script', - 'g:var = 123', - 'b:var = 456', - 'w:var = 777', - 't:var = 888', - 'unlet g:var w:var # something', - ]) - - v9.CheckScriptFailure([ - 'vim9script', - 'let var = 123', - ], 'E1126: Cannot use :let in Vim9 script') - - v9.CheckScriptFailure([ - 'vim9script', - 'var g:var = 123', - ], 'E1016: Cannot declare a global variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'var b:var = 123', - ], 'E1016: Cannot declare a buffer variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'var w:var = 123', - ], 'E1016: Cannot declare a window variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'var t:var = 123', - ], 'E1016: Cannot declare a tab variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'var v:version = 123', - ], 'E1016: Cannot declare a v: variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'var $VARIABLE = "text"', - ], 'E1016: Cannot declare an environment variable:') - - v9.CheckScriptFailure([ - 'vim9script', - 'g:var = 123', - 'unlet g:var# comment1', - ], 'E108:') - - v9.CheckScriptFailure([ - 'let g:var = 123', - 'unlet g:var # something', - ], 'E488:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'if 1 # comment2', - ' echo "yes"', - 'elseif 2 #comment', - ' echo "no"', - 'endif', - ]) - - v9.CheckScriptFailure([ - 'vim9script', - 'if 1# comment3', - ' echo "yes"', - 'endif', - ], 'E488:') - - v9.CheckScriptFailure([ - 'vim9script', - 'if 0 # comment4', - ' echo "yes"', - 'elseif 2#comment', - ' echo "no"', - 'endif', - ], 'E488:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'var v = 1 # comment5', - ]) - - v9.CheckScriptFailure([ - 'vim9script', - 'var v = 1# comment6', - ], 'E488:') - - v9.CheckScriptSuccess([ - 'vim9script', - 'new', - 'setline(1, ["# define pat", "last"])', - ':$', - 'dsearch /pat/ #comment', - 'bwipe!', - ]) - - v9.CheckScriptFailure([ - 'vim9script', - 'new', - 'setline(1, ["# define pat", "last"])', - ':$', - 'dsearch /pat/#comment', - 'bwipe!', - ], 'E488:') - - v9.CheckScriptFailure([ - 'vim9script', - 'func! SomeFunc()', - ], 'E477:') -enddef - -def Test_finish() - var lines =<< trim END - vim9script - g:res = 'one' - if v:false | finish | endif - g:res = 'two' - finish - g:res = 'three' - END - writefile(lines, 'Xfinished', 'D') - source Xfinished - assert_equal('two', g:res) - - unlet g:res -enddef - -def Test_forward_declaration() - var lines =<< trim END - vim9script - def GetValue(): string - return theVal - enddef - var theVal = 'something' - g:initVal = GetValue() - theVal = 'else' - g:laterVal = GetValue() - END - writefile(lines, 'Xforward', 'D') - source Xforward - assert_equal('something', g:initVal) - assert_equal('else', g:laterVal) - - unlet g:initVal - unlet g:laterVal -enddef - -def Test_declare_script_var_in_func() - var lines =<< trim END - vim9script - func Declare() - let s:local = 123 - endfunc - Declare() - END - v9.CheckScriptFailure(lines, 'E1269:') -enddef - -def Test_lock_script_var() - var lines =<< trim END - vim9script - var local = 123 - assert_equal(123, local) - - var error: string - try - local = 'asdf' - catch - error = v:exception - endtry - assert_match('E1012: Type mismatch; expected number but got string', error) - - lockvar local - try - local = 999 - catch - error = v:exception - endtry - assert_match('E741: Value is locked: local', error) - END - v9.CheckScriptSuccess(lines) -enddef - - -func Test_vim9script_not_global() - " check that items defined in Vim9 script are script-local, not global - let vim9lines =<< trim END - vim9script - var name = 'local' - func TheFunc() - echo 'local' - endfunc - def DefFunc() - echo 'local' - enddef - END - call writefile(vim9lines, 'Xvim9script.vim', 'D') - source Xvim9script.vim - try - echo g:var - assert_report('did not fail') - catch /E121:/ - " caught - endtry - try - call TheFunc() - assert_report('did not fail') - catch /E117:/ - " caught - endtry - try - call DefFunc() - assert_report('did not fail') - catch /E117:/ - " caught - endtry -endfunc - -def Test_vim9_copen() - CheckFeature quickfix - # this was giving an error for setting w:quickfix_title - copen - quit -enddef - -def Test_script_var_in_autocmd() - # using a script variable from an autocommand, defined in a :def function in a - # legacy Vim script, cannot check the variable type. - var lines =<< trim END - let s:counter = 1 - def s:Func() - au! CursorHold - au CursorHold * s:counter += 1 - enddef - call s:Func() - doau CursorHold - call assert_equal(2, s:counter) - au! CursorHold - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_error_in_autoload_script() - var save_rtp = &rtp - var dir = getcwd() .. '/Xruntime' - &rtp = dir - mkdir(dir .. '/autoload', 'pR') - - var lines =<< trim END - vim9script noclear - export def Autoloaded() - enddef - def Broken() - var x: any = '' - eval x != 0 - enddef - Broken() - END - writefile(lines, dir .. '/autoload/script.vim') - - lines =<< trim END - vim9script - def CallAutoloaded() - script#Autoloaded() - enddef - - function Legacy() - try - call s:CallAutoloaded() - catch - call assert_match('E1030: Using a String as a Number', v:exception) - endtry - endfunction - - Legacy() - END - v9.CheckScriptSuccess(lines) - - &rtp = save_rtp -enddef - -" Test for sourcing a Vim9 script with a function script variable and "noclear". -" The type for the variable is dynamically allocated and should be freed. -def Test_source_func_script_var() - var lines =<< trim END - vim9script noclear - var Fn: func(list<any>): any - Fn = function('min') - assert_equal(2, Fn([4, 2])) - END - new - setline(1, lines) - source - source - bw! -enddef - -def Test_error_in_autoload_script_foldexpr() - var save_rtp = &rtp - mkdir('Xvim/autoload', 'pR') - &runtimepath = 'Xvim' - - var lines =<< trim END - vim9script - eval [][0] - echomsg 'no error' - END - lines->writefile('Xvim/autoload/script.vim') - - lines =<< trim END - vim9script - import autoload 'script.vim' - &foldmethod = 'expr' - &foldexpr = 'script.Func()' - redraw - END - v9.CheckScriptFailure(lines, 'E684: List index out of range: 0') -enddef - -def Test_invalid_sid() - assert_fails('func <SNR>1234_func', 'E123:') - - if g:RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"') - assert_equal([], readfile('Xdidit')) - endif - delete('Xdidit') -enddef - -def Test_restoring_cpo() - writefile(['vim9script', 'set nocp'], 'Xsourced', 'D') - writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose', 'D') - if g:RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose') - assert_equal(['done'], readfile('Xdone')) - endif - delete('Xdone') - - writefile(['vim9script', 'g:cpoval = &cpo'], 'XanotherScript', 'D') - set cpo=aABceFsMny> - edit XanotherScript - so % - assert_equal('aABceFsMny>', &cpo) - assert_equal('aABceFsz', g:cpoval) - :1del - setline(1, 'let g:cpoval = &cpo') - w - so % - assert_equal('aABceFsMny>', &cpo) - assert_equal('aABceFsMny>', g:cpoval) - - set cpo&vim - unlet g:cpoval - - if has('unix') - # 'cpo' is not restored in main vimrc - var save_HOME = $HOME - $HOME = getcwd() .. '/Xhome' - mkdir('Xhome', 'R') - var lines =<< trim END - vim9script - writefile(['before: ' .. &cpo], 'Xrporesult') - set cpo+=M - writefile(['after: ' .. &cpo], 'Xrporesult', 'a') - END - writefile(lines, 'Xhome/.vimrc') - - lines =<< trim END - call writefile(['later: ' .. &cpo], 'Xrporesult', 'a') - END - writefile(lines, 'Xlegacy', 'D') - - lines =<< trim END - vim9script - call writefile(['vim9: ' .. &cpo], 'Xrporesult', 'a') - qa - END - writefile(lines, 'Xvim9', 'D') - - var cmd = g:GetVimCommand() .. " -S Xlegacy -S Xvim9" - cmd = substitute(cmd, '-u NONE', '', '') - exe "silent !" .. cmd - - assert_equal([ - 'before: aABceFsz', - 'after: aABceFszM', - 'later: aABceFszM', - 'vim9: aABceFsz'], readfile('Xrporesult')) - - $HOME = save_HOME - delete('Xrporesult') - endif -enddef - -" Use :function so we can use Check commands -func Test_no_redraw_when_restoring_cpo() - CheckScreendump - CheckFeature timers - call Run_test_no_redraw_when_restoring_cpo() -endfunc - -def Run_test_no_redraw_when_restoring_cpo() - CheckScreendump - var lines =<< trim END - vim9script - export def Func() - enddef - END - mkdir('Xnordir/autoload', 'pR') - writefile(lines, 'Xnordir/autoload/script.vim') - - lines =<< trim END - vim9script - set cpo+=M - exe 'set rtp^=' .. getcwd() .. '/Xnordir' - au CmdlineEnter : ++once timer_start(0, (_) => script#Func()) - setline(1, 'some text') - END - writefile(lines, 'XTest_redraw_cpo', 'D') - var buf = g:RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6}) - term_sendkeys(buf, "V:") - g:VerifyScreenDump(buf, 'Test_vim9_no_redraw', {}) - - # clean up - term_sendkeys(buf, "\<Esc>u") - g:StopVimInTerminal(buf) -enddef - -func Test_reject_declaration() - CheckScreendump - call Run_test_reject_declaration() -endfunc - -def Run_test_reject_declaration() - CheckScreendump - var buf = g:RunVimInTerminal('', {'rows': 6}) - term_sendkeys(buf, ":vim9cmd var x: number\<CR>") - g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_1', {}) - term_sendkeys(buf, ":\<CR>") - term_sendkeys(buf, ":vim9cmd g:foo = 123 | echo g:foo\<CR>") - g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_2', {}) - - # clean up - g:StopVimInTerminal(buf) -enddef - -def Test_minimal_command_name_length() - var names = [ - 'cons', - 'brea', - 'cat', - 'catc', - 'con', - 'cont', - 'conti', - 'contin', - 'continu', - 'el', - 'els', - 'elsei', - 'endfo', - 'en', - 'end', - 'endi', - 'endw', - 'endt', - 'endtr', - 'exp', - 'expo', - 'expor', - 'fina', - 'finall', - 'fini', - 'finis', - 'imp', - 'impo', - 'impor', - 'retu', - 'retur', - 'th', - 'thr', - 'thro', - 'wh', - 'whi', - 'whil', - ] - for name in names - v9.CheckDefAndScriptFailure([name .. ' '], 'E1065:') - endfor - - var lines =<< trim END - vim9script - def SomeFunc() - endd - END - v9.CheckScriptFailure(lines, 'E1065:') - lines =<< trim END - vim9script - def SomeFunc() - endde - END - v9.CheckScriptFailure(lines, 'E1065:') -enddef - -def Test_unset_any_variable() - var lines =<< trim END - var name: any - assert_equal(0, name) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -func Test_define_func_at_command_line() - CheckRunVimInTerminal - - " call indirectly to avoid compilation error for missing functions - call Run_Test_define_func_at_command_line() -endfunc - -def Run_Test_define_func_at_command_line() - # run in a separate Vim instance to avoid the script context - var lines =<< trim END - func CheckAndQuit() - call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc') - call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd') - endfunc - END - writefile([''], 'Xdidcmd', 'D') - writefile(lines, 'XcallFunc', 'D') - var buf = g:RunVimInTerminal('-S XcallFunc', {rows: 6}) - # define Afunc() on the command line - term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>") - term_sendkeys(buf, ":call CheckAndQuit()\<CR>") - g:WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd'))) - - call g:StopVimInTerminal(buf) -enddef - -def Test_script_var_scope() - var lines =<< trim END - vim9script - if true - if true - var one = 'one' - echo one - endif - echo one - endif - END - v9.CheckScriptFailure(lines, 'E121:', 7) - - lines =<< trim END - vim9script - if true - if false - var one = 'one' - echo one - else - var one = 'one' - echo one - endif - echo one - endif - END - v9.CheckScriptFailure(lines, 'E121:', 10) - - lines =<< trim END - vim9script - while true - var one = 'one' - echo one - break - endwhile - echo one - END - v9.CheckScriptFailure(lines, 'E121:', 7) - - lines =<< trim END - vim9script - for i in range(1) - var one = 'one' - echo one - endfor - echo one - END - v9.CheckScriptFailure(lines, 'E121:', 6) - - lines =<< trim END - vim9script - { - var one = 'one' - assert_equal('one', one) - } - assert_false(exists('one')) - assert_false(exists('s:one')) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - { - var one = 'one' - echo one - } - echo one - END - v9.CheckScriptFailure(lines, 'E121:', 6) -enddef - -def Test_catch_exception_in_callback() - var lines =<< trim END - vim9script - def Callback(...l: list<any>) - try - var x: string - var y: string - # this error should be caught with CHECKLEN - var sl = [''] - [x, y] = sl - catch - g:caught = 'yes' - endtry - enddef - popup_menu('popup', {callback: Callback}) - feedkeys("\r", 'xt') - END - v9.CheckScriptSuccess(lines) - - unlet g:caught -enddef - -def Test_no_unknown_error_after_error() - if !has('unix') || !has('job') - throw 'Skipped: not unix of missing +job feature' - endif - # FIXME: this check should not be needed - if has('win32') - throw 'Skipped: does not work on MS-Windows' - endif - var lines =<< trim END - vim9script - var source: list<number> - def Out_cb(...l: list<any>) - eval [][0] - enddef - def Exit_cb(...l: list<any>) - sleep 1m - g:did_call_exit_cb = true - source += l - enddef - var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'}) - while job_status(myjob) == 'run' - sleep 10m - endwhile - # wait for Exit_cb() to be called - for x in range(100) - if exists('g:did_call_exit_cb') - unlet g:did_call_exit_cb - break - endif - sleep 10m - endfor - END - writefile(lines, 'Xdef', 'D') - # Either the exit or out callback is called first, accept them in any order - assert_fails('so Xdef', ['E684:\|E1012:', 'E1012:\|E684:']) -enddef - -def InvokeNormal() - exe "norm! :m+1\r" -enddef - -def Test_invoke_normal_in_visual_mode() - xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR> - new - setline(1, ['aaa', 'bbb']) - feedkeys("V\<F3>", 'xt') - assert_equal(['bbb', 'aaa'], getline(1, 2)) - xunmap <F3> -enddef - -def Test_white_space_after_command() - var lines =<< trim END - exit_cb: Func}) - END - v9.CheckDefAndScriptFailure(lines, 'E1144:', 1) - - lines =<< trim END - e# - END - v9.CheckDefAndScriptFailure(lines, 'E1144:', 1) -enddef - -def Test_script_var_gone_when_sourced_twice() - var lines =<< trim END - vim9script - if exists('g:guard') - finish - endif - g:guard = 1 - var name = 'thename' - def g:GetName(): string - return name - enddef - def g:SetName(arg: string) - name = arg - enddef - END - writefile(lines, 'XscriptTwice.vim', 'D') - so XscriptTwice.vim - assert_equal('thename', g:GetName()) - g:SetName('newname') - assert_equal('newname', g:GetName()) - so XscriptTwice.vim - assert_fails('call g:GetName()', 'E1149:') - assert_fails('call g:SetName("x")', 'E1149:') - - delfunc g:GetName - delfunc g:SetName - unlet g:guard -enddef - -def Test_unsupported_commands() - var lines =<< trim END - ka - END - v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:']) - - lines =<< trim END - :1ka - END - v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:']) - - lines =<< trim END - :k a - END - v9.CheckDefAndScriptFailure(lines, 'E1100:') - - lines =<< trim END - :1k a - END - v9.CheckDefAndScriptFailure(lines, 'E481:') - - lines =<< trim END - t - END - v9.CheckDefAndScriptFailure(lines, 'E1100:') - - lines =<< trim END - x - END - v9.CheckDefAndScriptFailure(lines, 'E1100:') - - lines =<< trim END - xit - END - v9.CheckDefAndScriptFailure(lines, 'E1100:') - - lines =<< trim END - Print - END - v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: Print', 'E492: Not an editor command: Print']) - - lines =<< trim END - mode 4 - END - v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: mode 4', 'E492: Not an editor command: mode 4']) -enddef - -def Test_mapping_line_number() - var lines =<< trim END - vim9script - def g:FuncA() - # Some comment - FuncB(0) - enddef - # Some comment - def FuncB( - # Some comment - n: number - ) - exe 'nno ' - # Some comment - .. '<F3> a' - .. 'b' - .. 'c' - enddef - END - v9.CheckScriptSuccess(lines) - var res = execute('verbose nmap <F3>') - assert_match('No mapping found', res) - - g:FuncA() - res = execute('verbose nmap <F3>') - assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res) - - nunmap <F3> - delfunc g:FuncA -enddef - -def Test_option_set() - # legacy script allows for white space - var lines =<< trim END - set foldlevel =11 - call assert_equal(11, &foldlevel) - END - v9.CheckScriptSuccess(lines) - - set foldlevel - set foldlevel=12 - assert_equal(12, &foldlevel) - set foldlevel+=2 - assert_equal(14, &foldlevel) - set foldlevel-=3 - assert_equal(11, &foldlevel) - - lines =<< trim END - set foldlevel =1 - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1') - - lines =<< trim END - set foldlevel +=1 - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1') - - lines =<< trim END - set foldlevel ^=1 - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1') - - lines =<< trim END - set foldlevel -=1 - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1') - - set foldlevel& -enddef - -def Test_option_set_line_number() - var lines =<< trim END - vim9script - # line2 - # line3 - def F() - # line5 - &foldlevel = -128 - enddef - F() - END - v9.CheckScriptSuccess(lines) - - var res = execute('verbose set foldlevel') - assert_match(' foldlevel.*Last set from .*XScriptSuccess\d\+ line 6', res) -enddef - -def Test_option_modifier() - # legacy script allows for white space - var lines =<< trim END - set hlsearch & hlsearch ! - call assert_equal(1, &hlsearch) - END - v9.CheckScriptSuccess(lines) - - set hlsearch - set hlsearch! - assert_equal(false, &hlsearch) - - set hlsearch - set hlsearch& - assert_equal(false, &hlsearch) - - lines =<< trim END - set hlsearch & - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &') - - lines =<< trim END - set hlsearch ! - END - v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !') - - set hlsearch& -enddef - -" This must be called last, it may cause following :def functions to fail -def Test_xxx_echoerr_line_number() - var lines =<< trim END - echoerr 'some' - .. ' error' - .. ' continued' - END - v9.CheckDefExecAndScriptFailure(lines, 'some error continued', 1) -enddef - -func Test_debug_with_lambda() - CheckRunVimInTerminal - - " call indirectly to avoid compilation error for missing functions - call Run_Test_debug_with_lambda() -endfunc - -def Run_Test_debug_with_lambda() - var lines =<< trim END - vim9script - def Func() - var n = 0 - echo [0]->filter((_, v) => v == n) - enddef - breakadd func Func - Func() - END - writefile(lines, 'XdebugFunc', 'D') - var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 10, wait_for_ruler: 0}) - g:WaitForAssert(() => assert_match('^>', term_getline(buf, 10))) - - term_sendkeys(buf, "cont\<CR>") - g:WaitForAssert(() => assert_match('\[0\]', term_getline(buf, 9))) - - g:StopVimInTerminal(buf) -enddef - -func Test_debug_running_out_of_lines() - CheckRunVimInTerminal - - " call indirectly to avoid compilation error for missing functions - call Run_Test_debug_running_out_of_lines() -endfunc - -def Run_Test_debug_running_out_of_lines() - var lines =<< trim END - vim9script - def Crash() - # - # - # - # - # - # - # - if true - # - endif - enddef - breakadd func Crash - Crash() - END - writefile(lines, 'XdebugFunc', 'D') - var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 10, wait_for_ruler: 0}) - g:WaitForAssert(() => assert_match('^>', term_getline(buf, 10))) - - term_sendkeys(buf, "next\<CR>") - g:TermWait(buf) - g:WaitForAssert(() => assert_match('^>', term_getline(buf, 10))) - - term_sendkeys(buf, "cont\<CR>") - g:TermWait(buf) - - g:StopVimInTerminal(buf) -enddef - -def Test_ambiguous_command_error() - var lines =<< trim END - vim9script - command CmdA echomsg 'CmdA' - command CmdB echomsg 'CmdB' - Cmd - END - v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 4) - - lines =<< trim END - vim9script - def Func() - Cmd - enddef - Func() - END - v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 1) - - lines =<< trim END - vim9script - nnoremap <F3> <ScriptCmd>Cmd<CR> - feedkeys("\<F3>", 'xt') - END - v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 3) - - delcommand CmdA - delcommand CmdB - nunmap <F3> -enddef - -" Execute this near the end, profiling doesn't stop until Vim exits. -" This only tests that it works, not the profiling output. -def Test_profile_with_lambda() - CheckFeature profile - - var lines =<< trim END - vim9script - - def ProfiledWithLambda() - var n = 3 - echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) - enddef - - def ProfiledNested() - var x = 0 - def Nested(): any - return x - enddef - Nested() - enddef - - def g:ProfiledNestedProfiled() - var x = 0 - def Nested(): any - return x - enddef - Nested() - enddef - - def Profile() - ProfiledWithLambda() - ProfiledNested() - - # Also profile the nested function. Use a different function, although - # the contents is the same, to make sure it was not already compiled. - profile func * - g:ProfiledNestedProfiled() - - profdel func * - profile pause - enddef - - var result = 'done' - try - # mark functions for profiling now to avoid E1271 - profile start Xprofile.log - profile func ProfiledWithLambda - profile func ProfiledNested - - Profile() - catch - result = 'failed: ' .. v:exception - finally - writefile([result], 'Xdidprofile') - endtry - END - writefile(lines, 'Xprofile.vim', 'D') - call system(g:GetVimCommand() - .. ' --clean' - .. ' -c "so Xprofile.vim"' - .. ' -c "qall!"') - call assert_equal(0, v:shell_error) - - assert_equal(['done'], readfile('Xdidprofile')) - assert_true(filereadable('Xprofile.log')) - delete('Xdidprofile') - delete('Xprofile.log') -enddef - -func Test_misplaced_type() - CheckScreendump - CheckRunVimInTerminal - call Run_Test_misplaced_type() -endfunc - -def Run_Test_misplaced_type() - CheckScreendump - writefile(['let g:somevar = "asdf"'], 'XTest_misplaced_type', 'D') - var buf = g:RunVimInTerminal('-S XTest_misplaced_type', {'rows': 6}) - term_sendkeys(buf, ":vim9cmd echo islocked('somevar: string')\<CR>") - g:VerifyScreenDump(buf, 'Test_misplaced_type', {}) - - g:StopVimInTerminal(buf) -enddef - -" Ensure echo doesn't crash when stringifying empty variables. -def Test_echo_uninit_variables() - var res: string - - var var_bool: bool - var var_num: number - var var_float: float - var Var_func: func - var var_string: string - var var_blob: blob - var var_list: list<any> - var var_dict: dict<any> - - redir => res - echo var_bool - echo var_num - echo var_float - echo Var_func - echo var_string - echo var_blob - echo var_list - echo var_dict - redir END - - assert_equal(['false', '0', '0.0', 'function()', '', '0z', '[]', '{}'], res->split('\n')) - - if has('job') - var var_job: job - var var_channel: channel - - redir => res - echo var_job - echo var_channel - redir END - - assert_equal(['no process', 'channel fail'], res->split('\n')) - endif -enddef - -def Test_free_type_before_use() - # this rather complicated script was freeing a type before using it - var lines =<< trim END - vim9script - - def Scan(rel: list<dict<any>>): func(func(dict<any>)) - return (Emit: func(dict<any>)) => { - for t in rel - Emit(t) - endfor - } - enddef - - def Build(Cont: func(func(dict<any>))): list<dict<any>> - var rel: list<dict<any>> = [] - Cont((t) => { - add(rel, t) - }) - return rel - enddef - - var R = [{A: 0}] - var result = Scan(R)->Build() - result = Scan(R)->Build() - - assert_equal(R, result) - END - v9.CheckScriptSuccess(lines) -enddef - -" The following complicated script used to cause an internal error (E340) -" because the funcref instruction memory was referenced after the instruction -" memory was reallocated (Github issue #13178) -def Test_refer_funcref_instr_after_realloc() - var lines =<< trim END - vim9script - def A(d: bool) - var e = abs(0) - var f = &emoji - &emoji = true - if ['', '', '']->index('xxx') == 0 - eval 0 + 0 - endif - if &filetype == 'xxx' - var g = abs(0) - while g > 0 - if getline(g) == '' - break - endif - --g - endwhile - if g == 0 - return - endif - if d - feedkeys($'{g}G') - g = abs(0) - endif - var h = abs(0) - var i = abs(0) - var j = abs(0) - while j < 0 - if abs(0) < h && getline(j) != '' - break - endif - ++j - endwhile - feedkeys($'{g}G{j}G') - return - endif - def B() - enddef - def C() - enddef - enddef - A(false) - END - v9.CheckScriptSuccess(lines) -enddef - -" Test for calling a deferred function after an exception -def Test_defer_after_exception() - var lines =<< trim END - vim9script - - var callTrace: list<number> = [] - def Bar() - callTrace += [1] - throw 'InnerException' - enddef - - def Defer() - callTrace += [2] - callTrace += [3] - try - Bar() - catch /InnerException/ - callTrace += [4] - endtry - callTrace += [5] - callTrace += [6] - enddef - - def Foo() - defer Defer() - throw "TestException" - enddef - - try - Foo() - catch /TestException/ - callTrace += [7] - endtry - - assert_equal([2, 3, 1, 4, 5, 6, 7], callTrace) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for multiple deferred function which throw exceptions. -" Exceptions thrown by deferred functions should result in error messages but -" not propagated into the calling functions. -def Test_multidefer_with_exception() - var lines =<< trim END - vim9script - - var callTrace: list<number> = [] - def Except() - callTrace += [1] - throw 'InnerException' - callTrace += [2] - enddef - - def FirstDefer() - callTrace += [3] - callTrace += [4] - enddef - - def SecondDeferWithExcept() - callTrace += [5] - Except() - callTrace += [6] - enddef - - def ThirdDefer() - callTrace += [7] - callTrace += [8] - enddef - - def Foo() - callTrace += [9] - defer FirstDefer() - defer SecondDeferWithExcept() - defer ThirdDefer() - callTrace += [10] - enddef - - v:errmsg = '' - try - callTrace += [11] - Foo() - callTrace += [12] - catch /TestException/ - callTrace += [13] - catch - callTrace += [14] - finally - callTrace += [15] - endtry - callTrace += [16] - - assert_equal('E605: Exception not caught: InnerException', v:errmsg) - assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], callTrace) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using ":defer" inside an if statement with a false condition -def Test_defer_skipped() - var lines =<< trim END - def Foo() - if false - defer execute('echow "hello"', "") - endif - enddef - defcompile - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using defer without parenthesis for the function name -def Test_defer_func_without_paren() - var lines =<< trim END - vim9script - def Foo() - defer Bar - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E107: Missing parentheses: Bar', 1) -enddef - -" Test for using defer without parenthesis for the function name -def Test_defer_non_existing_func() - var lines =<< trim END - vim9script - def Foo() - defer Bar() - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1001: Variable not found: Bar', 1) -enddef - -" Test for using defer with an invalid function name -def Test_defer_invalid_func() - var lines =<< trim END - vim9script - def Foo() - var Abc = 10 - defer Abc() - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E129: Function name required', 2) -enddef - -" Test for using defer with an invalid argument to a function -def Test_defer_invalid_func_arg() - var lines =<< trim END - vim9script - def Bar(x: number) - enddef - def Foo() - defer Bar(a) - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1001: Variable not found: a', 1) -enddef - -" Test for using defer with a lambda funcref -def Test_defer_lambda_funcref() - var lines =<< trim END - vim9script - var lfr_result = '' - def Foo() - var Fn = () => { - lfr_result = 'called' - } - defer Fn() - enddef - Foo() - assert_equal('called', lfr_result) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using defer with a lambda and a command block -def Test_defer_lambda_func() - var lines =<< trim END - vim9script - var result = '' - def Foo() - result = 'xxx' - defer (a: number, b: string): number => { - result = $'{a}:{b}' - return 0 - }(10, 'aaa') - result = 'yyy' - enddef - Foo() - assert_equal('10:aaa', result) - END - v9.CheckScriptSuccess(lines) - - # Error: argument type mismatch - lines =<< trim END - vim9script - def Foo() - defer (a: number, b: string): number => { - return 0 - }(10, 20) - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number', 1) - - # Error: not enough arguments - lines =<< trim END - vim9script - def Foo() - defer (a: number) => { - }() - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E119: Not enough arguments for function: (a: number) => {', 1) - - # Error: too many arguments - lines =<< trim END - vim9script - def Foo() - defer () => { - }(10) - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E118: Too many arguments for function: () => {', 1) - - # Error: invalid command in command-block - lines =<< trim END - vim9script - def Foo() - defer () => { - xxx - }() - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E476: Invalid command: xxx', 1) - - # Error: missing return - lines =<< trim END - vim9script - def Foo() - defer (): number => { - }() - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1027: Missing return statement', 1) - - # Error: missing lambda body - lines =<< trim END - vim9script - def Foo() - defer (a: number): number - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1) - - # Error: invalid lambda syntax - lines =<< trim END - vim9script - def Foo() - defer ( - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1) - - # Error: lambda without arguments - lines =<< trim END - vim9script - def Foo() - defer () => { - } - assert_report("shouldn't reach here") - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E107: Missing parentheses: ', 1) -enddef - -" Test for using an non-existing type in a "for" statement. -def Test_invalid_type_in_for() - var lines =<< trim END - vim9script - def Foo() - for b: x in range(10) - endfor - enddef - defcompile - END - v9.CheckSourceFailure(lines, 'E1010: Type not recognized: x', 1) -enddef - -" Test for using a line break between the variable name and the type in a for -" statement. -def Test_for_stmt_space_before_type() - var lines =<< trim END - vim9script - def Foo() - for a - :number in range(10) - endfor - enddef - defcompile - END - v9.CheckSourceFailure(lines, 'E1059: No white space allowed before colon: :number in range(10)', 2) -enddef - -" This test used to cause a use-after-free memory access -def Test_for_empty_line_after_lambda() - var lines =<< trim END - vim9script - echomsg range(0, 2)->map((_, v) => { - return 1 - }) - - assert_equal('[1, 1, 1]', v:statusmsg) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - echomsg range(0, 1)->map((_, v) => { - return 1 - }) range(0, 1)->map((_, v) => { - return 2 - }) # comment - - assert_equal('[1, 1] [2, 2]', v:statusmsg) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for evaluating a lambda block from a string -def Test_eval_lambda_block() - var lines =<< trim END - vim9script - var Fn = eval("(x: number): number => {\nreturn x * 2\n}") - assert_equal(6, Fn(3)) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using various null values -def Test_null_values() - var lines =<< trim END - var nullValues = [ - [null, 1, 'null', 7, 'special'], - [null_blob, 1, '0z', 10, 'blob'], - [null_dict, 1, '{}', 4, 'dict<any>'], - [null_function, 1, "function('')", 2, 'func(...): unknown'], - [null_list, 1, '[]', 3, 'list<any>'], - [null_object, 1, 'object of [unknown]', 13, 'object<any>'], - [null_partial, 1, "function('')", 2, 'func(...): unknown'], - [null_string, 1, "''", 1, 'string'] - ] - if has('channel') - nullValues->add([null_channel, 1, 'channel fail', 9, 'channel']) - endif - if has('job') - nullValues->add([null_job, 1, 'no process', 8, 'job']) - endif - - for [Val, emptyExp, stringExp, typeExp, typenameExp] in nullValues - assert_equal(emptyExp, empty(Val)) - assert_equal(stringExp, string(Val)) - assert_equal(typeExp, type(Val)) - assert_equal(typenameExp, typename(Val)) - assert_equal(Val, copy(Val)) - assert_equal(-1, test_refcount(Val)) - endfor - END - v9.CheckSourceDefAndScriptSuccess(lines) -enddef - -" Test for using an unknown type in a typecast -def Test_unknown_type_in_typecast() - var lines =<< trim END - vim9script - var a = <MyType>b - END - v9.CheckSourceFailure(lines, 'E1010: Type not recognized: MyType', 2) - - lines =<< trim END - vim9script - var Fn = <funcx(number, number): number>b - END - v9.CheckSourceFailure(lines, 'E1010: Type not recognized: funcx(number, number): number', 2) - - # Wrong type in a type cast - lines =<< trim END - vim9script - var i: number = <number>true - END - v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got bool', 2) -enddef - -" Test for calling a function as a method with a list argument -" This exercises some conditions in the assignment statement parsing code. -def Test_method_call_with_list_arg() - var lines =<< trim END - vim9script - - def Foo(l: list<number>) - g:save_list = l - enddef - - def Bar() - var a = 10 - var b = 20 - [a, b]->Foo() - enddef - - g:save_list = [] - Bar() - assert_equal([10, 20], g:save_list) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using more than one has() check in a compound if condition. -def Test_has_func_shortcircuit() - var lines =<< trim END - vim9script - def Has_And1_Cond(): string - # true && false - if has('jumplist') && has('foobar') - return 'present' - endif - return 'missing' - enddef - assert_equal('missing', Has_And1_Cond()) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - def Has_And2_Cond(): string - # false && true - if has('foobar') && has('jumplist') - return 'present' - endif - return 'missing' - enddef - assert_equal('missing', Has_And2_Cond()) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - def Has_And3_Cond(): string - # false && false - if has('foobar') && has('foobaz') - return 'present' - endif - return 'missing' - enddef - assert_equal('missing', Has_And3_Cond()) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - def Has_Or1_Cond(): string - # true || false - if has('jumplist') || has('foobar') - return 'present' - endif - return 'missing' - enddef - assert_equal('present', Has_Or1_Cond()) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - def Has_Or2_Cond(): string - # false || true - if has('foobar') || has('jumplist') - return 'present' - endif - return 'missing' - enddef - assert_equal('present', Has_Or2_Cond()) - END - v9.CheckSourceSuccess(lines) - - lines =<< trim END - vim9script - def Has_Or3_Cond(): string - # false || false - if has('foobar') || has('foobaz') - return 'present' - endif - return 'missing' - enddef - assert_equal('missing', Has_Or3_Cond()) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for using more than one len() function in a compound if condition. -def Test_len_func_shortcircuit() - def Len_And1_Cond(): string - # true && false - if len('xxx') == 3 && len('yyy') == 2 - return 'match' - endif - return 'nomatch' - enddef - assert_equal('nomatch', Len_And1_Cond()) - - def Len_And2_Cond(): string - # false && true - if len('xxx') == 2 && len('yyy') == 3 - return 'match' - endif - return 'nomatch' - enddef - assert_equal('nomatch', Len_And2_Cond()) - - def Len_Or1_Cond(): string - # true || false - if len('xxx') == 3 || len('yyy') == 2 - return 'match' - endif - return 'nomatch' - enddef - assert_equal('match', Len_Or1_Cond()) - - def Len_Or2_Cond(): string - # false || true - if len('xxx') == 2 || len('yyy') == 3 - return 'match' - endif - return 'nomatch' - enddef - assert_equal('match', Len_Or2_Cond()) -enddef - -" Test for skipping list/tuple/dict/blob indexing when short circuiting a if -" condition check. -def Test_if_cond_shortcircuit_skip_indexing() - # indexing a list - var lines =<< trim END - vim9script - def Foo(): string - const l = [false] - if false && l[0] - return 'failed' - endif - if true || l[0] - return 'passed' - endif - return 'failed' - enddef - assert_equal('passed', Foo()) - END - v9.CheckSourceSuccess(lines) - - # indexing a tuple - lines =<< trim END - vim9script - def Foo(): string - const t = (false) - if false && t[0] - return 'failed' - endif - if true || t[0] - return 'passed' - endif - return 'failed' - enddef - assert_equal('passed', Foo()) - END - v9.CheckSourceSuccess(lines) - - # indexing a dict - lines =<< trim END - vim9script - def Foo(): string - const d = {x: false} - if false && d['x'] - return 'failed' - endif - if true || d['x'] - return 'passed' - endif - return 'failed' - enddef - assert_equal('passed', Foo()) - END - v9.CheckSourceSuccess(lines) - - # indexing a blob - lines =<< trim END - vim9script - def Foo(): string - const b = 0z00 - if false && b[0] - return 'failed' - endif - if true || b[0] - return 'passed' - endif - return 'failed' - enddef - assert_equal('passed', Foo()) - END - v9.CheckSourceSuccess(lines) -enddef - -" Test for defining a dict with multiple keys in a command-block -def Test_multikey_dict_in_block() - var lines =<< trim END - vim9script - command NewCommand { - g:TestDict = { - 'key': 'v1', - 'other_key': 'v2' } - } - NewCommand - END - v9.CheckSourceSuccess(lines) - assert_equal({key: 'v1', other_key: 'v2'}, g:TestDict) - unlet g:TestDict -enddef - -" Test for using the type() function with void -def Test_type_func_with_void() - var lines =<< trim END - vim9script - def GetVoidValue(): void - enddef - echo type(GetVoidValue()) - END - v9.CheckSourceFailure(lines, 'E1031: Cannot use void value', 4) -enddef - -" Keep this last, it messes up highlighting. -def Test_substitute_cmd() - new - setline(1, 'something') - :substitute(some(other( - assert_equal('otherthing', getline(1)) - bwipe! - - # also when the context is Vim9 script - var lines =<< trim END - vim9script - new - setline(1, 'something') - :substitute(some(other( - assert_equal('otherthing', getline(1)) - bwipe! - END - writefile(lines, 'Xvim9lines', 'D') - source Xvim9lines -enddef - -def Test_call_stack_string() - CheckScreendump - var lines =<< trim END - vim9script - - def CheckStack(stack: string, expected: string) - const caller = stack->split('\.\.')[-1]->substitute('\[\d\+\]', '', '') - if caller !~ expected - throw 'fail' - endif - enddef - - class C - static def ClassMethodX() - CheckStack(expand('<stack>'), '_C.ClassMethodX$') - enddef - endclass - - def NormalFuncX() - CheckStack(expand('<stack>'), '_NormalFuncX$') - enddef - - # creating function names of various lengths till the name in call stack is corrupt - for i in range(1, 20) - const name = 'Wrapper' .. repeat('A', i) .. 'func' - execute "def g:" .. name .. "(id: any)\n NormalFuncX()\n C.ClassMethodX()\nenddef" - execute "timer_start(0, g:" .. name .. ")" - endfor - END - writefile(lines, 'XTest_call_stack_string', 'D') - var buf = g:RunVimInTerminal('-S XTest_call_stack_string', {'rows': 20}) - g:StopVimInTerminal(buf) -enddef - -" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker |
