diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2018-05-10 19:18:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-10 19:18:58 +0200 |
commit | 8d40b3617c8bb10af5d4d4abcab0dfe77a4e807d (patch) | |
tree | cded38835bde85bc8a1682303617f84bf2549f7e | |
parent | 1cd8517344c0d99ca6fb3246c70f78d271993cf6 (diff) | |
parent | 966e7abc4960746b4dde618807fb5516d162ae2d (diff) | |
download | rneovim-8d40b3617c8bb10af5d4d4abcab0dfe77a4e807d.tar.gz rneovim-8d40b3617c8bb10af5d4d4abcab0dfe77a4e807d.tar.bz2 rneovim-8d40b3617c8bb10af5d4d4abcab0dfe77a4e807d.zip |
Merge #8371 'API: more reliable/descriptive VimL errors'
-rw-r--r-- | runtime/autoload/msgpack.vim | 12 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 4 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 104 | ||||
-rw-r--r-- | src/nvim/eval.c | 29 | ||||
-rw-r--r-- | src/nvim/ex_eval.c | 31 | ||||
-rw-r--r-- | test/functional/api/server_requests_spec.lua | 18 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 69 | ||||
-rw-r--r-- | test/functional/eval/buf_functions_spec.lua | 5 | ||||
-rw-r--r-- | test/functional/eval/match_functions_spec.lua | 7 | ||||
-rw-r--r-- | test/functional/eval/server_spec.lua | 16 | ||||
-rw-r--r-- | test/functional/legacy/file_perm_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/luaeval_spec.lua | 8 |
12 files changed, 192 insertions, 113 deletions
diff --git a/runtime/autoload/msgpack.vim b/runtime/autoload/msgpack.vim index a10ac32469..09c99c940d 100644 --- a/runtime/autoload/msgpack.vim +++ b/runtime/autoload/msgpack.vim @@ -40,9 +40,10 @@ function s:msgpack_init_python() abort return s:msgpack_python_type endif let s:msgpack_python_initialized = 1 - for suf in ['', '3'] + for suf in (has('win32') ? ['3'] : ['', '3']) try execute 'python' . suf + \. "\n" \. "def shada_dict_strftime():\n" \. " import datetime\n" \. " import vim\n" @@ -60,12 +61,15 @@ function s:msgpack_init_python() abort \. " fmt = vim.eval('a:format')\n" \. " timestr = vim.eval('a:string')\n" \. " timestamp = datetime.datetime.strptime(timestr, fmt)\n" - \. " timestamp = int(timestamp.timestamp())\n" + \. " try:\n" + \. " timestamp = int(timestamp.timestamp())\n" + \. " except:\n" + \. " timestamp = int(timestamp.strftime('%s'))\n" \. " if timestamp > 2 ** 31:\n" - \. " tsabs = abs(timestamp)" + \. " tsabs = abs(timestamp)\n" \. " return ('{\"_TYPE\": v:msgpack_types.integer,'\n" \. " + '\"_VAL\": [{sign},{v1},{v2},{v3}]}').format(\n" - \. " sign=1 if timestamp >= 0 else -1,\n" + \. " sign=(1 if timestamp >= 0 else -1),\n" \. " v1=((tsabs >> 62) & 0x3),\n" \. " v2=((tsabs >> 31) & (2 ** 31 - 1)),\n" \. " v3=(tsabs & (2 ** 31 - 1)))\n" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 12a4279dd7..637e24575d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -120,9 +120,7 @@ bool try_end(Error *err) // try_enter/try_leave. trylevel--; - // Without this it stops processing all subsequent VimL commands and - // generates strange error messages if I e.g. try calling Test() in a - // cycle + // Set by emsg(), affects aborting(). See also enter_cleanup(). did_emsg = false; if (got_int) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3679d1e569..fd9cf332d5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -46,8 +46,7 @@ /// Executes an ex-command. /// -/// On parse error: forwards the Vim error; does not update v:errmsg. -/// On runtime error: forwards the Vim error; does not update v:errmsg. +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any @@ -103,7 +102,8 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) } /// Passes input keys to Nvim. -/// On VimL error: Does not fail, but updates v:errmsg. +/// +/// On execution error: does not fail, but updates v:errmsg. /// /// @param keys to be typed /// @param mode mapping options @@ -169,7 +169,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) } /// Passes keys to Nvim as raw user-input. -/// On VimL error: Does not fail, but updates v:errmsg. +/// +/// On execution error: does not fail, but updates v:errmsg. /// /// Unlike `nvim_feedkeys`, this uses a lower-level input buffer and the call /// is not deferred. This is the most reliable way to send real user input. @@ -213,8 +214,7 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, /// Executes an ex-command and returns its (non-error) output. /// Shell |:!| output is not captured. /// -/// On parse error: forwards the Vim error; does not update v:errmsg. -/// On runtime error: forwards the Vim error; does not update v:errmsg. +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any @@ -259,7 +259,8 @@ theend: /// Evaluates a VimL expression (:help expression). /// Dictionaries and Lists are recursively expanded. -/// On VimL error: Returns a generic error; v:errmsg is not updated. +/// +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param expr VimL expression string /// @param[out] err Error details, if any @@ -267,22 +268,42 @@ theend: Object nvim_eval(String expr, Error *err) FUNC_API_SINCE(1) { + static int recursive = 0; // recursion depth Object rv = OBJECT_INIT; - // Evaluate the expression + + // `msg_list` controls the collection of abort-causing non-exception errors, + // which would otherwise be ignored. This pattern is from do_cmdline(). + struct msglist **saved_msg_list = msg_list; + struct msglist *private_msg_list; + msg_list = &private_msg_list; + private_msg_list = NULL; + + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + current_exception = NULL; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } + recursive++; try_start(); typval_T rettv; - if (eval0((char_u *)expr.data, &rettv, NULL, true) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to evaluate expression"); - } + int ok = eval0((char_u *)expr.data, &rettv, NULL, true); if (!try_end(err)) { - // No errors, convert the result - rv = vim_to_object(&rettv); + if (ok == FAIL) { + // Should never happen, try_end() should get the error. #8371 + api_set_error(err, kErrorTypeException, "Failed to evaluate expression"); + } else { + rv = vim_to_object(&rettv); + } } - // Free the Vim object tv_clear(&rettv); + msg_list = saved_msg_list; // Restore the exception context. + recursive--; return rv; } @@ -314,7 +335,9 @@ Object nvim_execute_lua(String code, Array args, Error *err) /// @return Result of the function call static Object _call_function(String fn, Array args, dict_T *self, Error *err) { + static int recursive = 0; // recursion depth Object rv = OBJECT_INIT; + if (args.size > MAX_FUNC_ARGS) { api_set_error(err, kErrorTypeValidation, "Function called with too many arguments"); @@ -330,20 +353,36 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err) } } + // `msg_list` controls the collection of abort-causing non-exception errors, + // which would otherwise be ignored. This pattern is from do_cmdline(). + struct msglist **saved_msg_list = msg_list; + struct msglist *private_msg_list; + msg_list = &private_msg_list; + private_msg_list = NULL; + + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + current_exception = NULL; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } + recursive++; try_start(); - // Call the function typval_T rettv; int dummy; - int r = call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size, - vim_args, NULL, curwin->w_cursor.lnum, - curwin->w_cursor.lnum, &dummy, true, NULL, self); - if (r == FAIL) { - api_set_error(err, kErrorTypeException, "Error calling function"); - } + // call_func() retval is deceptive, ignore it. Instead we set `msg_list` + // (see above) to capture abort-causing non-exception errors. + (void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size, + vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &dummy, true, NULL, self); if (!try_end(err)) { rv = vim_to_object(&rettv); } tv_clear(&rettv); + msg_list = saved_msg_list; // Restore the exception context. + recursive--; free_vim_args: while (i > 0) { @@ -355,7 +394,7 @@ free_vim_args: /// Calls a VimL function with the given arguments. /// -/// On VimL error: Returns a generic error; v:errmsg is not updated. +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param fn Function to call /// @param args Function arguments packed in an Array @@ -369,6 +408,8 @@ Object nvim_call_function(String fn, Array args, Error *err) /// Calls a VimL |Dictionary-function| with the given arguments. /// +/// On execution error: fails with VimL error, does not update v:errmsg. +/// /// @param dict Dictionary, or String evaluating to a VimL |self| dict /// @param fn Name of the function defined on the VimL dict /// @param args Function arguments packed in an Array @@ -934,27 +975,26 @@ Array nvim_get_api_info(uint64_t channel_id) return rv; } -/// Call many api methods atomically +/// Calls many API methods atomically. /// -/// This has two main usages: Firstly, to perform several requests from an -/// async context atomically, i.e. without processing requests from other rpc -/// clients or redrawing or allowing user interaction in between. Note that api -/// methods that could fire autocommands or do event processing still might do -/// so. For instance invoking the :sleep command might call timer callbacks. -/// Secondly, it can be used to reduce rpc overhead (roundtrips) when doing -/// many requests in sequence. +/// This has two main usages: +/// 1. To perform several requests from an async context atomically, i.e. +/// without interleaving redraws, RPC requests from other clients, or user +/// interactions (however API methods may trigger autocommands or event +/// processing which have such side-effects, e.g. |:sleep| may wake timers). +/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests. /// /// @param calls an array of calls, where each call is described by an array /// with two elements: the request name, and an array of arguments. /// @param[out] err Details of a validation error of the nvim_multi_request call -/// itself, i e malformatted `calls` parameter. Errors from called methods will +/// itself, i.e. malformed `calls` parameter. Errors from called methods will /// be indicated in the return value, see below. /// /// @return an array with two elements. The first is an array of return /// values. The second is NIL if all calls succeeded. If a call resulted in /// an error, it is a three-element array with the zero-based index of the call /// which resulted in an error, the error type and the error message. If an -/// error ocurred, the values from all preceding calls will still be returned. +/// error occurred, the values from all preceding calls will still be returned. Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index cc29496968..45a1776c86 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6241,20 +6241,21 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) /// invoked function uses them. It is called like this: /// new_argcount = argv_func(current_argcount, argv, called_func_argcount) /// -/// Return FAIL when the function can't be called, OK otherwise. -/// Also returns OK when an error was encountered while executing the function. +/// @return FAIL if function cannot be called, else OK (even if an error +/// occurred while executing the function! Set `msg_list` to capture +/// the error, see do_cmdline()). int call_func( const char_u *funcname, // name of the function int len, // length of "name" - typval_T *rettv, // return value goes here + typval_T *rettv, // [out] value goes here int argcount_in, // number of "argvars" typval_T *argvars_in, // vars for arguments, must have "argcount" // PLUS ONE elements! ArgvFunc argv_func, // function to fill in argvars linenr_T firstline, // first line of range linenr_T lastline, // last line of range - int *doesrange, // return: function handled range + int *doesrange, // [out] function handled range bool evaluate, partial_T *partial, // optional, can be NULL dict_T *selfdict_in // Dictionary for "self" @@ -6428,21 +6429,25 @@ call_func( return ret; } -/* - * Give an error message with a function name. Handle <SNR> things. - * "ermsg" is to be passed without translation, use N_() instead of _(). - */ +/// Give an error message with a function name. Handle <SNR> things. +/// +/// @param ermsg must be passed without translation (use N_() instead of _()). +/// @param name function name static void emsg_funcname(char *ermsg, char_u *name) { - char_u *p; + char_u *p; - if (*name == K_SPECIAL) + if (*name == K_SPECIAL) { p = concat_str((char_u *)"<SNR>", name + 3); - else + } else { p = name; + } + EMSG2(_(ermsg), p); - if (p != name) + + if (p != name) { xfree(p); + } } /* diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index e23945c842..7f7851f078 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -28,22 +28,21 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_eval.c.generated.h" #endif -/* - * Exception handling terms: - * - * :try ":try" command \ - * ... try block | - * :catch RE ":catch" command | - * ... catch clause |- try conditional - * :finally ":finally" command | - * ... finally clause | - * :endtry ":endtry" command / - * - * The try conditional may have any number of catch clauses and at most one - * finally clause. A ":throw" command can be inside the try block, a catch - * clause, the finally clause, or in a function called or script sourced from - * there or even outside the try conditional. Try conditionals may be nested. - */ + +// Exception handling terms: +// +// :try ":try" command ─┐ +// ... try block │ +// :catch RE ":catch" command │ +// ... catch clause ├─ try conditional +// :finally ":finally" command │ +// ... finally clause │ +// :endtry ":endtry" command ─┘ +// +// The try conditional may have any number of catch clauses and at most one +// finally clause. A ":throw" command can be inside the try block, a catch +// clause, the finally clause, or in a function called or script sourced from +// there or even outside the try conditional. Try conditionals may be nested. // Configuration whether an exception is thrown on error or interrupt. When // the preprocessor macros below evaluate to FALSE, an error (did_emsg) or diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 18229b54ff..e79a60fb10 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -11,6 +11,7 @@ local ok = helpers.ok local meths = helpers.meths local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv local set_session = helpers.set_session +local expect_err = helpers.expect_err describe('server -> client', function() local cid @@ -221,9 +222,8 @@ describe('server -> client', function() end) it('returns an error if the request failed', function() - local status, err = pcall(eval, "rpcrequest(vim, 'does-not-exist')") - eq(false, status) - ok(nil ~= string.match(err, 'Failed to evaluate expression')) + expect_err('Vim:Invalid method name', + eval, "rpcrequest(vim, 'does-not-exist')") end) end) @@ -250,7 +250,7 @@ describe('server -> client', function() end) after_each(function() - funcs.jobstop(jobid) + pcall(funcs.jobstop, jobid) end) if helpers.pending_win32(pending) then return end @@ -261,7 +261,7 @@ describe('server -> client', function() eq({'notification', 'pong', {}}, next_msg()) eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n")) eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_msg()) - funcs.rpcrequest(jobid, "exit") + pcall(funcs.rpcrequest, jobid, "exit") eq({'notification', 'stderr', {0, {''}}}, next_msg()) eq({'notification', 'exit', {0, 0}}, next_msg()) end) @@ -308,8 +308,8 @@ describe('server -> client', function() it('via ipv4 address', function() local server = spawn(nvim_argv) set_session(server) - local address = funcs.serverstart("127.0.0.1:") - if #address == 0 then + local status, address = pcall(funcs.serverstart, "127.0.0.1:") + if not status then pending('no ipv4 stack', function() end) return end @@ -320,8 +320,8 @@ describe('server -> client', function() it('via ipv6 address', function() local server = spawn(nvim_argv) set_session(server) - local address = funcs.serverstart('::1:') - if #address == 0 then + local status, address = pcall(funcs.serverstart, '::1:') + if not status then pending('no ipv6 stack', function() end) return end diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 0ff755b320..2d13506d6d 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -5,6 +5,7 @@ local global_helpers = require('test.helpers') local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq local command = helpers.command +local eval = helpers.eval local funcs = helpers.funcs local iswin = helpers.iswin local meth_pcall = helpers.meth_pcall @@ -40,20 +41,20 @@ describe('api', function() os.remove(fname) end) - it("parse error: fails (specific error), does NOT update v:errmsg", function() - -- Most API methods return generic errors (or no error) if a VimL - -- expression fails; nvim_command returns the VimL error details. + it('VimL validation error: fails with specific error', function() local status, rv = pcall(nvim, "command", "bogus_command") eq(false, status) -- nvim_command() failed. eq("E492:", string.match(rv, "E%d*:")) -- VimL error was returned. - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated. + eq('', eval('v:exception')) end) - it("runtime error: fails (specific error)", function() + it('VimL execution error: fails with specific error', function() local status, rv = pcall(nvim, "command_output", "buffer 23487") eq(false, status) -- nvim_command() failed. eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*")) - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + eq('', eval('v:errmsg')) -- v:errmsg was not updated. + eq('', eval('v:exception')) end) end) @@ -109,21 +110,21 @@ describe('api', function() eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]])) end) - it("parse error: fails (specific error), does NOT update v:errmsg", function() + it('VimL validation error: fails with specific error', function() local status, rv = pcall(nvim, "command_output", "bogus commannnd") eq(false, status) -- nvim_command_output() failed. eq("E492: Not an editor command: bogus commannnd", string.match(rv, "E%d*:.*")) - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + eq('', eval('v:errmsg')) -- v:errmsg was not updated. -- Verify NO hit-enter prompt. eq({mode='n', blocking=false}, nvim("get_mode")) end) - it("runtime error: fails (specific error)", function() + it('VimL execution error: fails with specific error', function() local status, rv = pcall(nvim, "command_output", "buffer 42") eq(false, status) -- nvim_command_output() failed. eq("E86: Buffer 42 does not exist", string.match(rv, "E%d*:.*")) - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + eq('', eval('v:errmsg')) -- v:errmsg was not updated. -- Verify NO hit-enter prompt. eq({mode='n', blocking=false}, nvim("get_mode")) end) @@ -145,11 +146,10 @@ describe('api', function() eq(2, request("vim_eval", "1+1")) end) - it("VimL error: fails (generic error), does NOT update v:errmsg", function() - local status, rv = pcall(nvim, "eval", "bogus expression") - eq(false, status) -- nvim_eval() failed. - ok(nil ~= string.find(rv, "Failed to evaluate expression")) - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + it("VimL error: returns error details, does NOT update v:errmsg", function() + expect_err('E121: Undefined variable: bogus', request, + 'nvim_eval', 'bogus expression') + eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) end) @@ -160,12 +160,39 @@ describe('api', function() eq(17, nvim('call_function', 'eval', {17})) eq('foo', nvim('call_function', 'simplify', {'this/./is//redundant/../../../foo'})) end) - it("VimL error: fails (generic error), does NOT update v:errmsg", function() - local status, rv = pcall(nvim, "call_function", "bogus function", {"arg1"}) - eq(false, status) -- nvim_call_function() failed. - ok(nil ~= string.find(rv, "Error calling function")) - eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + + it("VimL validation error: returns specific error, does NOT update v:errmsg", function() + expect_err('E117: Unknown function: bogus function', request, + 'nvim_call_function', 'bogus function', {'arg1'}) + expect_err('E119: Not enough arguments for function: atan', request, + 'nvim_call_function', 'atan', {}) + eq('', eval('v:exception')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. + end) + + it("VimL error: returns error details, does NOT update v:errmsg", function() + expect_err('E808: Number or Float required', request, + 'nvim_call_function', 'atan', {'foo'}) + expect_err('Invalid channel stream "xxx"', request, + 'nvim_call_function', 'chanclose', {999, 'xxx'}) + expect_err('E900: Invalid channel id', request, + 'nvim_call_function', 'chansend', {999, 'foo'}) + eq('', eval('v:exception')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) + + it("VimL exception: returns exception details, does NOT update v:errmsg", function() + source([[ + function! Foo() abort + throw 'wtf' + endfunction + ]]) + expect_err('wtf', request, + 'nvim_call_function', 'Foo', {}) + eq('', eval('v:exception')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. + end) + it('validates args', function() local too_many_args = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' } source([[ @@ -216,7 +243,7 @@ describe('api', function() 'nvim_call_dict_function', 'g:d', 'baz', {1,2}) expect_err('Not a function: meep', request, 'nvim_call_dict_function', 'g:d', 'meep', {1,2}) - expect_err('Error calling function', request, + expect_err('E117: Unknown function: f', request, 'nvim_call_dict_function', { f = '' }, 'f', {1,2}) expect_err('Not a function: f', request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', {1,2}) diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/eval/buf_functions_spec.lua index 7de58766b9..c0e264d4c9 100644 --- a/test/functional/eval/buf_functions_spec.lua +++ b/test/functional/eval/buf_functions_spec.lua @@ -15,6 +15,7 @@ local curwinmeths = helpers.curwinmeths local curtabmeths = helpers.curtabmeths local get_pathsep = helpers.get_pathsep local rmdir = helpers.rmdir +local expect_err = helpers.expect_err local fname = 'Xtest-functional-eval-buf_functions' local fname2 = fname .. '.2' @@ -296,8 +297,8 @@ describe('setbufvar() function', function() eq('Vim(call):E461: Illegal variable name: b:', exc_exec('call setbufvar(1, "", 0)')) eq(true, bufmeths.get_var(buf1, 'number')) - funcs.setbufvar(1, 'changedtick', true) - -- eq(true, bufmeths.get_var(buf1, 'changedtick')) + expect_err('Vim:E46: Cannot change read%-only variable "b:changedtick"', + funcs.setbufvar, 1, 'changedtick', true) eq(2, funcs.getbufvar(1, 'changedtick')) end) end) diff --git a/test/functional/eval/match_functions_spec.lua b/test/functional/eval/match_functions_spec.lua index 7989b22b5e..0ec465a34c 100644 --- a/test/functional/eval/match_functions_spec.lua +++ b/test/functional/eval/match_functions_spec.lua @@ -6,6 +6,7 @@ local clear = helpers.clear local funcs = helpers.funcs local command = helpers.command local exc_exec = helpers.exc_exec +local expect_err = helpers.expect_err before_each(clear) @@ -40,9 +41,11 @@ describe('setmatches()', function() end) it('fails with -1 if highlight group is not defined', function() - eq(-1, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}})) + expect_err('E28: No such highlight group name: 1', funcs.setmatches, + {{group=1, pattern=2, id=3, priority=4}}) eq({}, funcs.getmatches()) - eq(-1, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}})) + expect_err('E28: No such highlight group name: 1', funcs.setmatches, + {{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}) eq({}, funcs.getmatches()) end) end) diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua index 4e4aed864b..563e619b39 100644 --- a/test/functional/eval/server_spec.lua +++ b/test/functional/eval/server_spec.lua @@ -5,6 +5,7 @@ local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths local iswin = helpers.iswin local ok = helpers.ok local matches = helpers.matches +local expect_err = helpers.expect_err local function clear_serverlist() for _, server in pairs(funcs.serverlist()) do @@ -86,22 +87,23 @@ describe('server', function() local expected = {} local v4 = '127.0.0.1:12345' - s = funcs.serverstart(v4) - if #s > 0 then + local status, _ = pcall(funcs.serverstart, v4) + if status then table.insert(expected, v4) - funcs.serverstart(v4) -- exists already; ignore + pcall(funcs.serverstart, v4) -- exists already; ignore end local v6 = '::1:12345' - s = funcs.serverstart(v6) - if #s > 0 then + status, _ = pcall(funcs.serverstart, v6) + if status then table.insert(expected, v6) - funcs.serverstart(v6) -- exists already; ignore + pcall(funcs.serverstart, v6) -- exists already; ignore end eq(expected, funcs.serverlist()) clear_serverlist() - funcs.serverstart('127.0.0.1:65536') -- invalid port + expect_err('Failed to start server: invalid argument', + funcs.serverstart, '127.0.0.1:65536') -- invalid port eq({}, funcs.serverlist()) end) diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua index 77e82352c5..d61fdc9b83 100644 --- a/test/functional/legacy/file_perm_spec.lua +++ b/test/functional/legacy/file_perm_spec.lua @@ -15,7 +15,7 @@ describe('Test getting and setting file permissions', function() it('file permissions', function() eq('', call('getfperm', tempfile)) - eq(0, call('setfperm', tempfile, 'r------')) + eq(0, call('setfperm', tempfile, 'r--------')) call('writefile', {'one'}, tempfile) eq(9, call('len', call('getfperm', tempfile))) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 6da0001cea..760105df6b 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -51,12 +51,12 @@ describe('luaeval()', function() end) describe('recursive lua values', function() it('are successfully transformed', function() - funcs.luaeval('rawset(_G, "d", {})') - funcs.luaeval('rawset(d, "d", d)') + command('lua rawset(_G, "d", {})') + command('lua rawset(d, "d", d)') eq('\n{\'d\': {...@0}}', funcs.execute('echo luaeval("d")')) - funcs.luaeval('rawset(_G, "l", {})') - funcs.luaeval('table.insert(l, l)') + command('lua rawset(_G, "l", {})') + command('lua table.insert(l, l)') eq('\n[[...@0]]', funcs.execute('echo luaeval("l")')) end) end) |