To: vim_dev@googlegroups.com Subject: Patch 8.2.1146 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1146 Problem: Not enough testing for Python. Solution: Add more tests. Fix uncovered problems. (Yegappan Lakshmanan, closes #6392) Files: src/if_py_both.h, src/if_python3.c, src/testdir/shared.vim, src/testdir/test_python2.vim, src/testdir/test_python3.vim *** ../vim-8.2.1145/src/if_py_both.h 2020-06-29 23:07:40.046628613 +0200 --- src/if_py_both.h 2020-07-06 21:00:54.181681615 +0200 *************** *** 2250,2255 **** --- 2250,2258 ---- { ListObject *self; + if (list == NULL) + return NULL; + self = (ListObject *) subtype->tp_alloc(subtype, 0); if (self == NULL) return NULL; *************** *** 2695,2700 **** --- 2698,2709 ---- if (obj == NULL) { li = list_find(l, (long) index); + if (li == NULL) + { + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim " + "list item %d"), (int) index); + return -1; + } vimlist_remove(l, li, li); clear_tv(&li->li_tv); vim_free(li); *************** *** 2716,2721 **** --- 2725,2736 ---- else { li = list_find(l, (long) index); + if (li == NULL) + { + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim " + "list item %d"), (int) index); + return -1; + } clear_tv(&li->li_tv); copy_tv(&tv, &li->li_tv); clear_tv(&tv); *************** *** 3897,3903 **** PyObject_GC_UnTrack((void *)(self)); if (self->win && self->win != INVALID_WINDOW_VALUE) WIN_PYTHON_REF(self->win) = NULL; ! Py_XDECREF(((PyObject *)(self->tabObject))); PyObject_GC_Del((void *)(self)); } --- 3912,3918 ---- PyObject_GC_UnTrack((void *)(self)); if (self->win && self->win != INVALID_WINDOW_VALUE) WIN_PYTHON_REF(self->win) = NULL; ! Py_XDECREF(((PyObject *)(self->tabObject))); PyObject_GC_Del((void *)(self)); } *** ../vim-8.2.1145/src/if_python3.c 2020-03-29 20:51:03.081780739 +0200 --- src/if_python3.c 2020-07-06 21:00:54.181681615 +0200 *************** *** 1256,1261 **** --- 1256,1265 ---- if (PyLong_Check(idx)) { long n = PyLong_AsLong(idx); + + if (CheckBuffer((BufferObject *) self)) + return -1; + return RBAsItem((BufferObject *)(self), n, val, 1, (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count, NULL); *** ../vim-8.2.1145/src/testdir/shared.vim 2020-05-07 18:16:26.915943785 +0200 --- src/testdir/shared.vim 2020-07-06 21:00:54.181681615 +0200 *************** *** 353,356 **** --- 353,371 ---- return msg_list endfunc + " Run the list of commands in 'cmds' and look for 'errstr' in exception. + " Note that assert_fails() cannot be used in some places and this function + " can be used. + func AssertException(cmds, errstr) + let save_exception = '' + try + for cmd in a:cmds + exe cmd + endfor + catch + let save_exception = v:exception + endtry + call assert_match(a:errstr, save_exception) + endfunc + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-8.2.1145/src/testdir/test_python2.vim 2020-07-03 21:17:31.343914450 +0200 --- src/testdir/test_python2.vim 2020-07-06 21:00:54.185681601 +0200 *************** *** 3,8 **** --- 3,9 ---- source check.vim CheckFeature python CheckFeature quickfix + source shared.vim " NOTE: This will cause errors when run under valgrind. " This would require recompiling Python with: *************** *** 55,67 **** endfunc func Test_pydo() ! " Check deleting lines does not trigger ml_get error. new call setline(1, ['one', 'two', 'three']) pydo vim.command("%d_") bwipe! ! " Check switching to another buffer does not trigger ml_get error. new let wincount = winnr('$') call setline(1, ['one', 'two', 'three']) --- 56,68 ---- endfunc func Test_pydo() ! " Check deleting lines does not trigger an ml_get error. new call setline(1, ['one', 'two', 'three']) pydo vim.command("%d_") bwipe! ! " Check switching to another buffer does not trigger an ml_get error. new let wincount = winnr('$') call setline(1, ['one', 'two', 'three']) *************** *** 69,74 **** --- 70,88 ---- call assert_equal(wincount + 1, winnr('$')) bwipe! bwipe! + + " Try modifying a buffer with 'nomodifiable' set + set nomodifiable + call assert_fails('pydo toupper(line)', 'cannot save undo information') + set modifiable + + " Invalid command + call AssertException(['pydo non_existing_cmd'], + \ "Vim(pydo):NameError: global name 'non_existing_cmd' is not defined") + call AssertException(["pydo raise Exception('test')"], + \ 'Vim(pydo):Exception: test') + call AssertException(["pydo {lambda}"], + \ 'Vim(pydo):SyntaxError: invalid syntax') endfunc func Test_set_cursor() *************** *** 106,119 **** call assert_false(v:exception) endtry ! let caught_vim_err = v:false ! try ! let x = pyeval('f.abc') ! catch ! call assert_match('AttributeError: abc', v:exception) ! let caught_vim_err = v:true ! endtry ! call assert_equal(v:true, caught_vim_err) py del f delfunc s:foo --- 120,128 ---- call assert_false(v:exception) endtry ! " Non-existing function attribute ! call AssertException(["let x = pyeval('f.abc')"], ! \ 'Vim(let):AttributeError: abc') py del f delfunc s:foo *************** *** 250,255 **** --- 259,267 ---- py r = b.range(1, 3) call assert_equal(0, pyeval('r.start')) call assert_equal(2, pyeval('r.end')) + call assert_equal('one', pyeval('r[0]')) + call assert_equal('one', pyeval('r[-3]')) + call assert_equal('three', pyeval('r[-4]')) call assert_equal(['two', 'three'], pyeval('r[1:]')) py r[0] = 'green' call assert_equal(['green', 'two', 'three'], getline(1, '$')) *************** *** 257,270 **** call assert_equal(['red', 'blue', 'three'], getline(1, '$')) call assert_equal(['start', 'end', '__members__'], pyeval('r.__members__')) ! let caught_vim_err = v:false ! try ! let x = pyeval('r.abc') ! catch ! call assert_match('AttributeError: abc', v:exception) ! let caught_vim_err = v:true ! endtry ! call assert_equal(v:true, caught_vim_err) close! endfunc --- 269,290 ---- call assert_equal(['red', 'blue', 'three'], getline(1, '$')) call assert_equal(['start', 'end', '__members__'], pyeval('r.__members__')) ! " try different invalid start/end index for the range slice ! %d ! call setline(1, ['one', 'two', 'three']) ! py r[-10:1] = ["a"] ! py r[10:12] = ["b"] ! py r[-10:-9] = ["c"] ! py r[1:0] = ["d"] ! call assert_equal(['c', 'd', 'a', 'two', 'three', 'b'], getline(1, '$')) ! ! " FIXME: The following code triggers ml_get errors ! " %d ! " let x = pyeval('r[:]') ! ! " Non-existing range attribute ! call AssertException(["let x = pyeval('r.abc')"], ! \ 'Vim(let):AttributeError: abc') close! endfunc *************** *** 273,305 **** func Test_python_tabpage() tabnew py t = vim.tabpages[1] tabclose ! let caught_vim_err = v:false ! try ! let n = pyeval('t.number') ! catch ! call assert_match('vim.error: attempt to refer to deleted tab page', ! \ v:exception) ! let caught_vim_err = v:true ! endtry ! call assert_equal(v:true, caught_vim_err) %bw! endfunc " Test for the python window object func Test_python_window() ! new py w = vim.current.window close ! let caught_vim_err = v:false ! try ! let n = pyeval('w.number') ! catch ! call assert_match('vim.error: attempt to refer to deleted window', ! \ v:exception) ! let caught_vim_err = v:true ! endtry ! call assert_equal(v:true, caught_vim_err) endfunc " Test for the python List object --- 293,342 ---- func Test_python_tabpage() tabnew py t = vim.tabpages[1] + py wl = t.windows tabclose ! " Accessing a closed tabpage ! call AssertException(["let n = pyeval('t.number')"], ! \ 'Vim(let):vim.error: attempt to refer to deleted tab page') ! call AssertException(["let n = pyeval('len(wl)')"], ! \ 'Vim(let):vim.error: attempt to refer to deleted tab page') ! call AssertException(["py w = wl[0]"], ! \ 'Vim(python):vim.error: attempt to refer to deleted tab page') ! call AssertException(["py vim.current.tabpage = t"], ! \ 'Vim(python):vim.error: attempt to refer to deleted tab page') ! call assert_match(', , ]", substitute(pyeval('repr(dv)'),'0x\x\+','','g')) *************** *** 552,557 **** --- 640,650 ---- EOF call assert_equal(['', "l[2] threw vim.error: error:('list is locked',)"], \ getline(1, '$')) + + " Try to concatenate a locked list + call AssertException(['py l += [4, 5]'], + \ 'Vim(python):vim.error: list is locked') + call assert_equal([0, 1, 2, 3], l) unlockvar! l close! *************** *** 665,670 **** --- 758,768 ---- call assert_equal([0], l) call assert_equal([1], ll) unlet l ll + + " Try changing an attribute of a fixed list + py a = vim.bindeval('v:argv') + call AssertException(['py a.locked = 0'], + \ 'Vim(python):TypeError: cannot modify fixed list') endfunc " Test for pyeval() *************** *** 679,720 **** call assert_equal(v:none, pyeval('None')) call assert_equal('', v:errmsg) if has('float') call assert_equal(0.0, pyeval('0.0')) endif ! " Invalid values: ! let caught_859 = 0 ! try ! let v = pyeval('"\0"') ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) ! ! let caught_859 = 0 ! try ! let v = pyeval('{"\0" : 1}') ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) ! ! let caught_nameerr = 0 ! try ! let v = pyeval("undefined_name") ! catch /NameError: name 'undefined_name'/ ! let caught_nameerr = 1 ! endtry ! call assert_equal(1, caught_nameerr) ! ! let caught_859 = 0 ! try ! let v = pyeval("vim") ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) endfunc " threading --- 777,814 ---- call assert_equal(v:none, pyeval('None')) call assert_equal('', v:errmsg) + py v = vim.eval('test_null_function()') + call assert_equal(v:none, pyeval('v')) + if has('float') call assert_equal(0.0, pyeval('0.0')) endif ! " Evaluate an invalid values ! call AssertException(['let v = pyeval(''"\0"'')'], 'E859:') ! call AssertException(['let v = pyeval(''{"\0" : 1}'')'], 'E859:') ! call AssertException(['let v = pyeval("undefined_name")'], ! \ "Vim(let):NameError: name 'undefined_name' is not defined") ! call AssertException(['let v = pyeval("vim")'], 'E859:') ! endfunc ! ! " Test for vim.bindeval() ! func Test_python_vim_bindeval() ! " Float ! let f = 3.14 ! py f = vim.bindeval('f') ! call assert_equal(3.14, pyeval('f')) ! ! " Blob ! let b = 0z12 ! py b = vim.bindeval('b') ! call assert_equal("\x12", pyeval('b')) ! ! " Bool ! call assert_equal(1, pyeval("vim.bindeval('v:true')")) ! call assert_equal(0, pyeval("vim.bindeval('v:false')")) ! call assert_equal(v:none, pyeval("vim.bindeval('v:null')")) ! call assert_equal(v:none, pyeval("vim.bindeval('v:none')")) endfunc " threading *************** *** 812,818 **** --- 906,929 ---- call assert_equal([0, 2, 4], pyeval('l')) py l = ll[4:2:1] call assert_equal([], pyeval('l')) + + " Error case: Use an invalid index + call AssertException(['py ll[-10] = 5'], 'Vim(python):vim.error: internal error:') + + " Use a step value of 0 + call AssertException(['py ll[0:3:0] = [1, 2, 3]'], + \ 'Vim(python):ValueError: slice step cannot be zero') + + " Error case: Invalid slice type + call AssertException(["py x = ll['abc']"], + \ 'Vim(python):TypeError: index must be int or slice, not str') py del l + + " Error case: List with a null list item + let l = [test_null_list()] + py ll = vim.bindeval('l') + call AssertException(["py x = ll[:]"], + \ 'Vim(python):SystemError: error return without exception set') endfunc " Vars *************** *** 1249,1254 **** --- 1360,1383 ---- call assert_equal(expected, g:res) unlet g:res + + call assert_equal(0, pyeval("'' in vim.options")) + + " use an empty key to index vim.options + call AssertException(["let v = pyeval(\"vim.options['']\")"], + \ 'Vim(let):ValueError: empty keys are not allowed') + call AssertException(["py vim.current.window.options[''] = 0"], + \ 'Vim(python):ValueError: empty keys are not allowed') + call AssertException(["py vim.current.window.options[{}] = 0"], + \ 'Vim(python):TypeError: expected str() or unicode() instance, but got dict') + + " set one of the number options to a very large number + let cmd = ["py vim.options['previewheight'] = 9999999999999999"] + call AssertException(cmd, 'OverflowError:') + + " unset a global-local string option + call AssertException(["py del vim.options['errorformat']"], + \ 'Vim(python):ValueError: unable to unset global option errorformat') endfunc " Test for vim.buffer object *************** *** 1267,1277 **** --- 1396,1421 ---- py b = vim.current.buffer wincmd w + " Test for getting lines from the buffer using a slice + call assert_equal(['First line'], pyeval('b[-10:1]')) + call assert_equal(['Third line'], pyeval('b[2:10]')) + call assert_equal([], pyeval('b[2:0]')) + call assert_equal([], pyeval('b[10:12]')) + call assert_equal([], pyeval('b[-10:-8]')) + " Tests BufferAppend and BufferItem py cb.append(b[0]) call assert_equal(['First line'], getbufline(bnr1, 2)) %d + " Try to append using out-of-range line number + call AssertException(["py b.append('abc', 10)"], + \ 'Vim(python):IndexError: line number out of range') + + " Append a non-string item + call AssertException(["py b.append([22])"], + \ 'Vim(python):TypeError: expected str() or unicode() instance, but got int') + " Tests BufferSlice and BufferAssSlice py cb.append('abc5') # Will be overwritten py cb[-1:] = b[:-2] *************** *** 1363,1373 **** --- 1507,1568 ---- EOF call assert_equal([''], getline(1, '$')) + " Delete all the lines in a buffer + call setline(1, ['a', 'b', 'c']) + py vim.current.buffer[:] = [] + call assert_equal([''], getline(1, '$')) + + " Test for modifying a 'nomodifiable' buffer + setlocal nomodifiable + call AssertException(["py vim.current.buffer[0] = 'abc'"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[0] = None"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[:] = None"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[:] = []"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer.append('abc')"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer.append([])"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + setlocal modifiable + augroup BUFS autocmd! augroup END augroup! BUFS %bw! + + " Range object for a deleted buffer + new Xfile + call setline(1, ['one', 'two', 'three']) + py b = vim.current.buffer + py r = vim.current.buffer.range(0, 2) + call assert_equal('', pyeval('repr(r)')) + %bw! + call AssertException(['py r[:] = []'], + \ 'Vim(python):vim.error: attempt to refer to deleted buffer') + call assert_match(' Buffer") cb.append(">> StringToLine (indirect)") - ee('vim.current.buffer[0] = u"\\na"') ee('vim.current.buffer[0] = "\\na"') cb.append(">> SetBufferLine (indirect)") ee('vim.current.buffer[0] = True') cb.append(">> SetBufferLineList (indirect)") --- 2738,2745 ---- ee('vim.windows[1000]') cb.append("> Buffer") cb.append(">> StringToLine (indirect)") ee('vim.current.buffer[0] = "\\na"') + ee('vim.current.buffer[0] = u"\\na"') cb.append(">> SetBufferLine (indirect)") ee('vim.current.buffer[0] = True') cb.append(">> SetBufferLineList (indirect)") *************** *** 3360,3367 **** vim.windows[1000]:IndexError:('no such window',) > Buffer >> StringToLine (indirect) - vim.current.buffer[0] = u"\na":error:('string cannot contain newlines',) vim.current.buffer[0] = "\na":error:('string cannot contain newlines',) >> SetBufferLine (indirect) vim.current.buffer[0] = True:TypeError:('bad argument type for built-in operation',) >> SetBufferLineList (indirect) --- 3561,3568 ---- vim.windows[1000]:IndexError:('no such window',) > Buffer >> StringToLine (indirect) vim.current.buffer[0] = "\na":error:('string cannot contain newlines',) + vim.current.buffer[0] = u"\na":error:('string cannot contain newlines',) >> SetBufferLine (indirect) vim.current.buffer[0] = True:TypeError:('bad argument type for built-in operation',) >> SetBufferLineList (indirect) *************** *** 3442,3447 **** --- 3643,3649 ---- cb.append(tm.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):]) cb.append(tms.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):]) cb.append(tmsss.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):]) + del before del after del d *************** *** 3463,3475 **** END call assert_equal(expected, getline(2, '$')) close! endfunc " Test exceptions func Test_python_exception() ! fun Exe(e) execute a:e ! endfun new py cb = vim.current.buffer --- 3665,3680 ---- END call assert_equal(expected, getline(2, '$')) close! + + " Try to import a non-existing moudle with a dot (.) + call AssertException(['py import a.b.c'], 'ImportError:') endfunc " Test exceptions func Test_python_exception() ! func Exe(e) execute a:e ! endfunc new py cb = vim.current.buffer *** ../vim-8.2.1145/src/testdir/test_python3.vim 2020-07-03 21:17:31.343914450 +0200 --- src/testdir/test_python3.vim 2020-07-06 21:00:54.185681601 +0200 *************** *** 2,7 **** --- 2,8 ---- source check.vim CheckFeature python3 + source shared.vim " This function should be called first. This sets up python functions used by " the other tests. *************** *** 73,79 **** func Test_py3do() " Check deleting lines does not trigger an ml_get error. - py3 import vim new call setline(1, ['one', 'two', 'three']) py3do vim.command("%d_") --- 74,79 ---- *************** *** 87,97 **** call assert_equal(wincount + 1, winnr('$')) bwipe! bwipe! endfunc func Test_set_cursor() " Check that setting the cursor position works. - py3 import vim new call setline(1, ['first line', 'second line']) normal gg --- 87,109 ---- call assert_equal(wincount + 1, winnr('$')) bwipe! bwipe! + + " Try modifying a buffer with 'nomodifiable' set + set nomodifiable + call assert_fails('py3do toupper(line)', 'cannot save undo information') + set modifiable + + " Invalid command + call AssertException(['py3do non_existing_cmd'], + \ "Vim(py3do):NameError: name 'non_existing_cmd' is not defined") + call AssertException(["py3do raise Exception('test')"], + \ 'Vim(py3do):Exception: test') + call AssertException(["py3do {lambda}"], + \ 'Vim(py3do):SyntaxError: invalid syntax') endfunc func Test_set_cursor() " Check that setting the cursor position works. new call setline(1, ['first line', 'second line']) normal gg *************** *** 105,111 **** func Test_vim_function() " Check creating vim.Function object - py3 import vim func s:foo() return matchstr(expand(''), '\zs\d\+_foo$') --- 117,122 ---- *************** *** 126,139 **** call assert_false(v:exception) endtry ! let caught_vim_err = v:false ! try ! let x = py3eval('f.abc') ! catch ! call assert_match("AttributeError: 'vim.function' object has no attribute 'abc'", v:exception) ! let caught_vim_err = v:true ! endtry ! call assert_equal(v:true, caught_vim_err) py3 del f delfunc s:foo --- 137,145 ---- call assert_false(v:exception) endtry ! " Non-existing function attribute ! call AssertException(["let x = py3eval('f.abc')"], ! \ "Vim(let):AttributeError: 'vim.function' object has no attribute 'abc'") py3 del f delfunc s:foo *************** *** 148,154 **** endfunc func _SetUpHiddenBuffer() - py3 import vim new edit hidden setlocal bufhidden=hide --- 154,159 ---- *************** *** 198,204 **** endfunc func _SetUpVisibleBuffer() - py3 import vim new let lnum = 0 while lnum < 10 --- 203,208 ---- *************** *** 303,310 **** call assert_fails('py3 r[3] = "x"', 'IndexError: line number out of range') call assert_fails('py3 x = r[3]', 'IndexError: line number out of range') ! call assert_fails('py3 r["a"] = "x"', 'TypeError') ! call assert_fails('py3 x = r["a"]', 'TypeError') py3 del r[:] call assert_equal(['1', '5', '6'], getline(1, '$')) --- 307,314 ---- call assert_fails('py3 r[3] = "x"', 'IndexError: line number out of range') call assert_fails('py3 x = r[3]', 'IndexError: line number out of range') ! call assert_fails('py3 r["a"] = "x"', 'TypeError: index must be int or slice, not str') ! call assert_fails('py3 x = r["a"]', 'TypeError: index must be int or slice, not str') py3 del r[:] call assert_equal(['1', '5', '6'], getline(1, '$')) *************** *** 431,438 **** --- 435,546 ---- call assert_equal('ABCDE', pyxeval('s')) endfunc + " Test for the buffer range object + func Test_python3_range2() + new + call setline(1, ['one', 'two', 'three']) + py3 b = vim.current.buffer + py3 r = b.range(1, 3) + call assert_equal(0, py3eval('r.start')) + call assert_equal(2, py3eval('r.end')) + call assert_equal('one', py3eval('r[0]')) + call assert_equal('one', py3eval('r[-3]')) + call AssertException(["let x = py3eval('r[-4]')"], + \ 'Vim(let):IndexError: line number out of range') + call assert_equal(['two', 'three'], py3eval('r[1:]')) + py3 r[0] = 'green' + call assert_equal(['green', 'two', 'three'], getline(1, '$')) + py3 r[0:2] = ['red', 'blue'] + call assert_equal(['red', 'blue', 'three'], getline(1, '$')) + + " try different invalid start/end index for the range slice + %d + call setline(1, ['one', 'two', 'three']) + py3 r[-10:1] = ["a"] + py3 r[10:12] = ["b"] + py3 r[-10:-9] = ["c"] + py3 r[1:0] = ["d"] + call assert_equal(['c', 'd', 'a', 'two', 'three', 'b'], getline(1, '$')) + + " FIXME: The following code triggers ml_get errors + " %d + " let x = py3eval('r[:]') + + " Non-existing range attribute + call AssertException(["let x = py3eval('r.abc')"], + \ "Vim(let):AttributeError: 'vim.range' object has no attribute 'abc'") + + close! + endfunc + + " Test for the python tabpage object + func Test_python3_tabpage() + tabnew + py3 t = vim.tabpages[1] + py3 wl = t.windows + tabclose + " Accessing a closed tabpage + call AssertException(["let n = py3eval('t.number')"], + \ 'Vim(let):vim.error: attempt to refer to deleted tab page') + call AssertException(["let n = py3eval('len(wl)')"], + \ 'Vim(let):vim.error: attempt to refer to deleted tab page') + call AssertException(["py3 w = wl[0]"], + \ 'Vim(py3):vim.error: attempt to refer to deleted tab page') + call AssertException(["py3 vim.current.tabpage = t"], + \ 'Vim(py3):vim.error: attempt to refer to deleted tab page') + call assert_match(' returned NULL without setting an error') + + " Try to convert a List with a null List item + call AssertException(["py3 t = vim.eval('[test_null_list()]')"], + \ 'Vim(py3):SystemError: returned NULL without setting an error') + + " Try to bind a null List variable + let cmds =<< trim END + let l = test_null_list() + py3 ll = vim.bindeval('l') + END + call AssertException(cmds, + \ 'Vim(py3):SystemError: returned NULL without setting an error') + let l = [] py3 l = vim.bindeval('l') py3 f = vim.bindeval('function("strlen")') *************** *** 447,452 **** --- 555,593 ---- call assert_equal([0, "as'd", [1, 2, function("strlen"), {'a': 1}]], l) py3 l[-2] = f call assert_equal([0, function("strlen"), [1, 2, function("strlen"), {'a': 1}]], l) + + " appending to a list + let l = [1, 2] + py3 ll = vim.bindeval('l') + py3 ll[2] = 8 + call assert_equal([1, 2, 8], l) + + " Using dict as an index + call AssertException(['py3 ll[{}] = 10'], + \ 'Vim(py3):TypeError: index must be int or slice, not dict') + endfunc + + " Test for the python Dict object + func Test_python3_dict() + " Try to convert a null Dict + call AssertException(["py3 t = vim.eval('test_null_dict()')"], + \ 'Vim(py3):SystemError: returned NULL without setting an error') + + " Try to convert a Dict with a null List value + call AssertException(["py3 t = vim.eval(\"{'a' : test_null_list()}\")"], + \ 'Vim(py3):SystemError: returned NULL without setting an error') + + " Try to convert a Dict with a null string key + py3 t = vim.eval("{test_null_string() : 10}") + call assert_fails("let d = py3eval('t')", 'E859:') + + " Dict length + let d = {'a' : 10, 'b' : 20} + py3 d = vim.bindeval('d') + call assert_equal(2, py3eval('len(d)')) + + " Deleting an non-existing key + call AssertException(["py3 del d['c']"], "Vim(py3):KeyError: 'c'") endfunc " Extending Dictionary directly with different types *************** *** 472,477 **** --- 613,624 ---- di.sort(key=repr) EOF + " Try extending a locked dictionary + lockvar d + call AssertException(["py3 d.update({'b' : 20})"], + \ 'Vim(py3):vim.error: dictionary is locked') + unlockvar d + call assert_equal(1, py3eval("d['f'](self={})")) call assert_equal("[b'-1', b'0', b'1', b'b', b'f']", py3eval('repr(dk)')) call assert_equal("[-1, , , , b'asd']", substitute(py3eval('repr(dv)'),'0x\x\+','','g')) *************** *** 668,673 **** --- 815,824 ---- EOF call assert_equal(['', "l[2] threw vim.error: error:('list is locked',)"], \ getline(1, '$')) + + " Try to concatenate a locked list + call AssertException(['py3 l += [4, 5]'], 'Vim(py3):vim.error: list is locked') + call assert_equal([0, 1, 2, 3], l) unlockvar! l close! *************** *** 785,790 **** --- 936,946 ---- call assert_equal([0], l) call assert_equal([1], ll) unlet l ll + + " Try changing an attribute of a fixed list + py3 a = vim.bindeval('v:argv') + call AssertException(['py3 a.locked = 0'], + \ 'Vim(py3):TypeError: cannot modify fixed list') endfunc " Test for py3eval() *************** *** 799,846 **** call assert_equal(v:none, py3eval('None')) call assert_equal('', v:errmsg) if has('float') call assert_equal(0.0, py3eval('0.0')) endif ! " Invalid values: ! let caught_859 = 0 ! try ! let v = py3eval('"\0"') ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) ! ! let caught_859 = 0 ! try ! let v = py3eval('{"\0" : 1}') ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) ! ! let caught_nameerr = 0 ! try ! let v = py3eval("undefined_name") ! catch /NameError: name 'undefined_name'/ ! let caught_nameerr = 1 ! endtry ! call assert_equal(1, caught_nameerr) ! ! let caught_859 = 0 ! try ! let v = py3eval("vim") ! catch /E859:/ ! let caught_859 = 1 ! endtry ! call assert_equal(1, caught_859) endfunc " threading " Running py3do command (Test_pydo) before this test, stops the python thread " from running. So this test should be run before the pydo test ! func Test_aaa_python_threading() let l = [0] py3 l = vim.bindeval('l') py3 << trim EOF --- 955,998 ---- call assert_equal(v:none, py3eval('None')) call assert_equal('', v:errmsg) + py3 v = vim.eval('test_null_function()') + call assert_equal(v:none, py3eval('v')) + if has('float') call assert_equal(0.0, py3eval('0.0')) endif ! " Evaluate an invalid values ! call AssertException(['let v = py3eval(''"\0"'')'], 'E859:') ! call AssertException(['let v = py3eval(''{"\0" : 1}'')'], 'E859:') ! call AssertException(['let v = py3eval("undefined_name")'], ! \ "Vim(let):NameError: name 'undefined_name' is not defined") ! call AssertException(['let v = py3eval("vim")'], 'E859:') ! endfunc ! ! " Test for vim.bindeval() ! func Test_python3_vim_bindeval() ! " Float ! let f = 3.14 ! py3 f = vim.bindeval('f') ! call assert_equal(3.14, py3eval('f')) ! ! " Blob ! let b = 0z12 ! py3 b = vim.bindeval('b') ! call assert_equal("\x12", py3eval('b')) ! ! " Bool ! call assert_equal(1, py3eval("vim.bindeval('v:true')")) ! call assert_equal(0, py3eval("vim.bindeval('v:false')")) ! call assert_equal(v:none, py3eval("vim.bindeval('v:null')")) ! call assert_equal(v:none, py3eval("vim.bindeval('v:none')")) endfunc " threading " Running py3do command (Test_pydo) before this test, stops the python thread " from running. So this test should be run before the pydo test ! func Test_aaa_python3_threading() let l = [0] py3 l = vim.bindeval('l') py3 << trim EOF *************** *** 932,938 **** --- 1084,1107 ---- call assert_equal([0, 2, 4], py3eval('l')) py3 l = ll[4:2:1] call assert_equal([], py3eval('l')) + + " Error case: Use an invalid index + call AssertException(['py3 ll[-10] = 5'], 'Vim(py3):vim.error: internal error:') + + " Use a step value of 0 + call AssertException(['py3 ll[0:3:0] = [1, 2, 3]'], + \ 'Vim(py3):ValueError: slice step cannot be zero') + + " Error case: Invalid slice type + call AssertException(["py3 x = ll['abc']"], + \ "Vim(py3):TypeError: index must be int or slice, not str") py3 del l + + " Error case: List with a null list item + let l = [test_null_list()] + py3 ll = vim.bindeval('l') + call AssertException(["py3 x = ll[:]"], + \ "Vim(py3):SystemError: error return without exception set") endfunc " Vars *************** *** 1369,1374 **** --- 1538,1561 ---- call assert_equal(expected, g:res) unlet g:res + + call assert_equal(0, py3eval("'' in vim.options")) + + " use an empty key to index vim.options + call AssertException(["let v = py3eval(\"vim.options['']\")"], + \ 'Vim(let):ValueError: empty keys are not allowed') + call AssertException(["py3 vim.current.window.options[''] = 0"], + \ 'Vim(py3):ValueError: empty keys are not allowed') + call AssertException(["py3 vim.current.window.options[{}] = 0"], + \ 'Vim(py3):TypeError: expected bytes() or str() instance, but got dict') + + " set one of the number options to a very large number + let cmd = ["py3 vim.options['previewheight'] = 9999999999999999"] + call AssertException(cmd, "Vim(py3):OverflowError:") + + " unset a global-local string option + call AssertException(["py3 del vim.options['errorformat']"], + \ 'Vim(py3):ValueError: unable to unset global option errorformat') endfunc " Test for vim.buffer object *************** *** 1387,1397 **** --- 1574,1599 ---- py3 b = vim.current.buffer wincmd w + " Test for getting lines from the buffer using a slice + call assert_equal(['First line'], py3eval('b[-10:1]')) + call assert_equal(['Third line'], py3eval('b[2:10]')) + call assert_equal([], py3eval('b[2:0]')) + call assert_equal([], py3eval('b[10:12]')) + call assert_equal([], py3eval('b[-10:-8]')) + " Tests BufferAppend and BufferItem py3 cb.append(b[0]) call assert_equal(['First line'], getbufline(bnr1, 2)) %d + " Try to append using out-of-range line number + call AssertException(["py3 b.append('abc', 10)"], + \ 'Vim(py3):IndexError: line number out of range') + + " Append a non-string item + call AssertException(["py3 b.append([22])"], + \ 'Vim(py3):TypeError: expected bytes() or str() instance, but got int') + " Tests BufferSlice and BufferAssSlice py3 cb.append('abc5') # Will be overwritten py3 cb[-1:] = b[:-2] *************** *** 1483,1493 **** --- 1685,1746 ---- EOF call assert_equal([''], getline(1, '$')) + " Delete all the lines in a buffer + call setline(1, ['a', 'b', 'c']) + py3 vim.current.buffer[:] = [] + call assert_equal([''], getline(1, '$')) + + " Test for modifying a 'nomodifiable' buffer + setlocal nomodifiable + call AssertException(["py3 vim.current.buffer[0] = 'abc'"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py3 vim.current.buffer[0] = None"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py3 vim.current.buffer[:] = None"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py3 vim.current.buffer[:] = []"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py3 vim.current.buffer.append('abc')"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py3 vim.current.buffer.append([])"], + \ "Vim(py3):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + setlocal modifiable + augroup BUFS autocmd! augroup END augroup! BUFS %bw! + + " Range object for a deleted buffer + new Xfile + call setline(1, ['one', 'two', 'three']) + py3 b = vim.current.buffer + py3 r = vim.current.buffer.range(0, 2) + call assert_equal('', py3eval('repr(r)')) + %bw! + call AssertException(['py3 r[:] = []'], + \ 'Vim(py3):vim.error: attempt to refer to deleted buffer') + call assert_match('