Merge pull request #3943 from ZyX-I/better-fref-error

eval: Use better error messages when failing to dump values
This commit is contained in:
Justin M. Keyes
2016-01-08 09:29:37 -05:00
7 changed files with 153 additions and 47 deletions

View File

@@ -4712,7 +4712,7 @@ msgpackdump({list}) {Nvim} *msgpackdump()*
(dictionary with zero items is represented by 0x80 byte in (dictionary with zero items is represented by 0x80 byte in
messagepack). messagepack).
Limitations: Limitations: *E951* *E952*
1. |Funcref|s cannot be dumped. 1. |Funcref|s cannot be dumped.
2. Containers that reference themselves cannot be dumped. 2. Containers that reference themselves cannot be dumped.
3. Dictionary keys are always dumped as STR strings. 3. Dictionary keys are always dumped as STR strings.

View File

@@ -6479,7 +6479,8 @@ failret:
static int name##_convert_one_value(firstargtype firstargname, \ static int name##_convert_one_value(firstargtype firstargname, \
MPConvStack *const mpstack, \ MPConvStack *const mpstack, \
typval_T *const tv, \ typval_T *const tv, \
const int copyID) \ const int copyID, \
const char *const objname) \
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
{ \ { \
switch (tv->v_type) { \ switch (tv->v_type) { \
@@ -6713,14 +6714,16 @@ name##_convert_one_value_regular_dict: \
return OK; \ return OK; \
} \ } \
\ \
scope int vim_to_##name(firstargtype firstargname, typval_T *const tv) \ scope int vim_to_##name(firstargtype firstargname, typval_T *const tv, \
const char *const objname) \
FUNC_ATTR_WARN_UNUSED_RESULT \ FUNC_ATTR_WARN_UNUSED_RESULT \
{ \ { \
current_copyID += COPYID_INC; \ current_copyID += COPYID_INC; \
const int copyID = current_copyID; \ const int copyID = current_copyID; \
MPConvStack mpstack; \ MPConvStack mpstack; \
kv_init(mpstack); \ kv_init(mpstack); \
if (name##_convert_one_value(firstargname, &mpstack, tv, copyID) == FAIL) { \ if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
== FAIL) { \
goto vim_to_msgpack_error_ret; \ goto vim_to_msgpack_error_ret; \
} \ } \
while (kv_size(mpstack)) { \ while (kv_size(mpstack)) { \
@@ -6769,8 +6772,8 @@ scope int vim_to_##name(firstargtype firstargname, typval_T *const tv) \
} \ } \
const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \ const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
if (name##_convert_one_value(firstargname, &mpstack, \ if (name##_convert_one_value(firstargname, &mpstack, \
&kv_pair->lv_first->li_tv, copyID) \ &kv_pair->lv_first->li_tv, copyID, \
== FAIL) { \ objname) == FAIL) { \
goto vim_to_msgpack_error_ret; \ goto vim_to_msgpack_error_ret; \
} \ } \
cur_tv = &kv_pair->lv_last->li_tv; \ cur_tv = &kv_pair->lv_last->li_tv; \
@@ -6778,8 +6781,8 @@ scope int vim_to_##name(firstargtype firstargname, typval_T *const tv) \
break; \ break; \
} \ } \
} \ } \
if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID) \ if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
== FAIL) { \ objname) == FAIL) { \
goto vim_to_msgpack_error_ret; \ goto vim_to_msgpack_error_ret; \
} \ } \
} \ } \
@@ -6975,7 +6978,7 @@ static char *tv2string(typval_T *tv, size_t *len)
{ {
garray_T ga; garray_T ga;
ga_init(&ga, (int)sizeof(char), 80); ga_init(&ga, (int)sizeof(char), 80);
vim_to_string(&ga, tv); vim_to_string(&ga, tv, "tv2string() argument");
did_echo_string_emsg = false; did_echo_string_emsg = false;
if (len != NULL) { if (len != NULL) {
*len = (size_t) ga.ga_len; *len = (size_t) ga.ga_len;
@@ -7001,7 +7004,7 @@ static char *echo_string(typval_T *tv, size_t *len)
ga_concat(&ga, tv->vval.v_string); ga_concat(&ga, tv->vval.v_string);
} }
} else { } else {
vim_to_echo(&ga, tv); vim_to_echo(&ga, tv, ":echo argument");
did_echo_string_emsg = false; did_echo_string_emsg = false;
} }
if (len != NULL) { if (len != NULL) {
@@ -12686,6 +12689,77 @@ static inline bool vim_list_to_buf(const list_T *const list,
return true; return true;
} }
/// Show a error message when converting to msgpack value
///
/// @param[in] msg Error message to dump. Must contain exactly two %s that
/// will be replaced with what was being dumped: first with
/// something like “F” or “function argument”, second with path
/// to the failed value.
/// @param[in] mpstack Path to the failed value.
/// @param[in] objname Dumped object name.
///
/// @return FAIL.
static int conv_error(const char *const msg, const MPConvStack *const mpstack,
const char *const objname)
FUNC_ATTR_NONNULL_ALL
{
garray_T msg_ga;
ga_init(&msg_ga, (int)sizeof(char), 80);
char *const key_msg = _("key %s");
char *const key_pair_msg = _("key %s at index %i from special map");
char *const idx_msg = _("index %i");
for (size_t i = 0; i < kv_size(*mpstack); i++) {
if (i != 0) {
ga_concat(&msg_ga, (char_u *) ", ");
}
MPConvStackVal v = kv_A(*mpstack, i);
switch (v.type) {
case kMPConvDict: {
typval_T key_tv = {
.v_type = VAR_STRING,
.vval = { .v_string = (v.data.d.hi == NULL
? v.data.d.dict->dv_hashtab.ht_array
: (v.data.d.hi - 1))->hi_key },
};
char *const key = tv2string(&key_tv, NULL);
vim_snprintf((char *) IObuff, IOSIZE, key_msg, key);
xfree(key);
ga_concat(&msg_ga, IObuff);
break;
}
case kMPConvPairs:
case kMPConvList: {
int idx = 0;
const listitem_T *li;
for (li = v.data.l.list->lv_first;
li != NULL && li->li_next != v.data.l.li;
li = li->li_next) {
idx++;
}
if (v.type == kMPConvList
|| li == NULL
|| (li->li_tv.v_type != VAR_LIST
&& li->li_tv.vval.v_list->lv_len <= 0)) {
vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx);
ga_concat(&msg_ga, IObuff);
} else {
typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv;
char *const key = echo_string(&key_tv, NULL);
vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
xfree(key);
ga_concat(&msg_ga, IObuff);
}
break;
}
}
}
EMSG3(msg, objname, (kv_size(*mpstack) == 0
? _("itself")
: (char *) msg_ga.ga_data));
ga_clear(&msg_ga);
return FAIL;
}
#define CONV_STRING(buf, len) \ #define CONV_STRING(buf, len) \
do { \ do { \
if (buf == NULL) { \ if (buf == NULL) { \
@@ -12726,10 +12800,9 @@ static inline bool vim_list_to_buf(const list_T *const list,
msgpack_pack_double(packer, (double) (flt)) msgpack_pack_double(packer, (double) (flt))
#define CONV_FUNC(fun) \ #define CONV_FUNC(fun) \
do { \ return conv_error(_("E951: Error while dumping %s, %s: " \
EMSG2(_(e_invarg2), "attempt to dump function reference"); \ "attempt to dump function reference"), \
return FAIL; \ mpstack, objname)
} while (0)
#define CONV_EMPTY_LIST() \ #define CONV_EMPTY_LIST() \
msgpack_pack_array(packer, 0) msgpack_pack_array(packer, 0)
@@ -12772,10 +12845,9 @@ static inline bool vim_list_to_buf(const list_T *const list,
#define CONV_LIST_BETWEEN_ITEMS(lst) #define CONV_LIST_BETWEEN_ITEMS(lst)
#define CONV_RECURSE(val, conv_type) \ #define CONV_RECURSE(val, conv_type) \
do { \ return conv_error(_("E952: Unable to dump %s: " \
EMSG2(_(e_invarg2), "container references itself"); \ "container references itself in %s"), \
return FAIL; \ mpstack, objname)
} while (0)
#define CONV_ALLOW_SPECIAL true #define CONV_ALLOW_SPECIAL true
@@ -12817,8 +12889,14 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv)
return; return;
} }
msgpack_packer *lpacker = msgpack_packer_new(ret_list, &msgpack_list_write); msgpack_packer *lpacker = msgpack_packer_new(ret_list, &msgpack_list_write);
const char *const msg = _("msgpackdump() argument, index %i");
// Assume that translation will not take more then 4 times more space
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
int idx = 0;
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) { for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
if (vim_to_msgpack(lpacker, &li->li_tv) == FAIL) { vim_snprintf(msgbuf, sizeof(msgbuf), (char *) msg, idx);
idx++;
if (vim_to_msgpack(lpacker, &li->li_tv, msgbuf) == FAIL) {
break; break;
} }
} }

View File

@@ -118,7 +118,8 @@ enum {
/// Maximum number of function arguments /// Maximum number of function arguments
#define MAX_FUNC_ARGS 20 #define MAX_FUNC_ARGS 20
int vim_to_msgpack(msgpack_packer *const, typval_T *const); int vim_to_msgpack(msgpack_packer *const, typval_T *const,
const char *const objname);
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.h.generated.h" # include "eval.h.generated.h"

View File

@@ -1684,17 +1684,18 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
msgpack_sbuffer sbuf; msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf); msgpack_sbuffer_init(&sbuf);
msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write); msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write);
#define DUMP_ADDITIONAL_ELEMENTS(src) \ #define DUMP_ADDITIONAL_ELEMENTS(src, what) \
do { \ do { \
if ((src) != NULL) { \ if ((src) != NULL) { \
for (listitem_T *li = (src)->lv_first; li != NULL; li = li->li_next) { \ for (listitem_T *li = (src)->lv_first; li != NULL; li = li->li_next) { \
if (vim_to_msgpack(spacker, &li->li_tv) == FAIL) { \ if (vim_to_msgpack(spacker, &li->li_tv, \
_("additional elements of ShaDa " what)) == FAIL) { \
goto shada_pack_entry_error; \ goto shada_pack_entry_error; \
} \ } \
} \ } \
} \ } \
} while (0) } while (0)
#define DUMP_ADDITIONAL_DATA(src) \ #define DUMP_ADDITIONAL_DATA(src, what) \
do { \ do { \
dict_T *const d = (src); \ dict_T *const d = (src); \
if (d != NULL) { \ if (d != NULL) { \
@@ -1706,7 +1707,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
const size_t key_len = strlen((const char *) hi->hi_key); \ const size_t key_len = strlen((const char *) hi->hi_key); \
msgpack_pack_str(spacker, key_len); \ msgpack_pack_str(spacker, key_len); \
msgpack_pack_str_body(spacker, (const char *) hi->hi_key, key_len); \ msgpack_pack_str_body(spacker, (const char *) hi->hi_key, key_len); \
if (vim_to_msgpack(spacker, &di->di_tv) == FAIL) { \ if (vim_to_msgpack(spacker, &di->di_tv, \
_("additional data of ShaDa " what)) == FAIL) { \
goto shada_pack_entry_error; \ goto shada_pack_entry_error; \
} \ } \
} \ } \
@@ -1741,7 +1743,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
if (is_hist_search) { if (is_hist_search) {
msgpack_pack_uint8(spacker, (uint8_t) entry.data.history_item.sep); msgpack_pack_uint8(spacker, (uint8_t) entry.data.history_item.sep);
} }
DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements); DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
"history entry item");
break; break;
} }
case kSDItemVariable: { case kSDItemVariable: {
@@ -1750,14 +1753,20 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
? 0 ? 0
: entry.data.global_var.additional_elements->lv_len); : entry.data.global_var.additional_elements->lv_len);
msgpack_pack_array(spacker, arr_size); msgpack_pack_array(spacker, arr_size);
PACK_BIN(cstr_as_string(entry.data.global_var.name)); const String varname = cstr_as_string(entry.data.global_var.name);
if (vim_to_msgpack(spacker, &entry.data.global_var.value) == FAIL) { PACK_BIN(varname);
char vardesc[256] = "variable g:";
memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
varname.size + 1);
if (vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
== FAIL) {
ret = kSDWriteIgnError; ret = kSDWriteIgnError;
EMSG2(_(WERR "Failed to write variable %s"), EMSG2(_(WERR "Failed to write variable %s"),
entry.data.global_var.name); entry.data.global_var.name);
goto shada_pack_entry_error; goto shada_pack_entry_error;
} }
DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements); DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
"variable item");
break; break;
} }
case kSDItemSubString: { case kSDItemSubString: {
@@ -1767,7 +1776,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
: entry.data.sub_string.additional_elements->lv_len); : entry.data.sub_string.additional_elements->lv_len);
msgpack_pack_array(spacker, arr_size); msgpack_pack_array(spacker, arr_size);
PACK_BIN(cstr_as_string(entry.data.sub_string.sub)); PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements); DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
"sub string item");
break; break;
} }
case kSDItemSearchPattern: { case kSDItemSearchPattern: {
@@ -1814,7 +1824,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
msgpack_pack_int64(spacker, entry.data.search_pattern.offset); msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
} }
#undef PACK_BOOL #undef PACK_BOOL
DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data); DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
"search pattern item");
break; break;
} }
case kSDItemChange: case kSDItemChange:
@@ -1849,7 +1860,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
PACK_STATIC_STR(KEY_NAME_CHAR); PACK_STATIC_STR(KEY_NAME_CHAR);
msgpack_pack_uint8(spacker, (uint8_t) entry.data.filemark.name); msgpack_pack_uint8(spacker, (uint8_t) entry.data.filemark.name);
} }
DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data); DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
"mark (change, jump, global or local) item");
break; break;
} }
case kSDItemRegister: { case kSDItemRegister: {
@@ -1877,7 +1889,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
PACK_STATIC_STR(REG_KEY_WIDTH); PACK_STATIC_STR(REG_KEY_WIDTH);
msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width); msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width);
} }
DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data); DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
break; break;
} }
case kSDItemBufferList: { case kSDItemBufferList: {
@@ -1908,7 +1920,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
msgpack_pack_uint64( msgpack_pack_uint64(
spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.col); spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.col);
} }
DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data); DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
"buffer list subitem");
} }
break; break;
} }

View File

@@ -541,27 +541,27 @@ describe('msgpackdump() function', function()
it('fails to dump a function reference', function() it('fails to dump a function reference', function()
execute('let Todump = function("tr")') execute('let Todump = function("tr")')
eq('Vim(call):E475: Invalid argument: attempt to dump function reference', eq('Vim(call):E951: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',
exc_exec('call msgpackdump([Todump])')) exc_exec('call msgpackdump([Todump])'))
end) end)
it('fails to dump a function reference in a list', function() it('fails to dump a function reference in a list', function()
execute('let todump = [function("tr")]') execute('let todump = [function("tr")]')
eq('Vim(call):E475: Invalid argument: attempt to dump function reference', eq('Vim(call):E951: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
it('fails to dump a recursive list', function() it('fails to dump a recursive list', function()
execute('let todump = [[[]]]') execute('let todump = [[[]]]')
execute('call add(todump[0][0], todump)') execute('call add(todump[0][0], todump)')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
it('fails to dump a recursive dict', function() it('fails to dump a recursive dict', function()
execute('let todump = {"d": {"d": {}}}') execute('let todump = {"d": {"d": {}}}')
execute('call extend(todump.d.d, {"d": todump})') execute('call extend(todump.d.d, {"d": todump})')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
@@ -580,21 +580,35 @@ describe('msgpackdump() function', function()
it('fails to dump a recursive list in a special dict', function() it('fails to dump a recursive list in a special dict', function()
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
execute('call add(todump._VAL, todump)') execute('call add(todump._VAL, todump)')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
it('fails to dump a recursive (key) map in a special dict', function() it('fails to dump a recursive (key) map in a special dict', function()
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
execute('call add(todump._VAL, [todump, 0])') execute('call add(todump._VAL, [todump, 0])')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 1',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
it('fails to dump a recursive (val) map in a special dict', function() it('fails to dump a recursive (val) map in a special dict', function()
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
execute('call add(todump._VAL, [0, todump])') execute('call add(todump._VAL, [0, todump])')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (key) map in a special dict, _VAL reference', function()
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
execute('call add(todump._VAL[0][0], todump._VAL)')
eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
execute('call add(todump._VAL[0][1], todump._VAL)')
eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)
@@ -602,7 +616,7 @@ describe('msgpackdump() function', function()
function() function()
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
execute('call add(todump._VAL, [0, todump._VAL])') execute('call add(todump._VAL, [0, todump._VAL])')
eq('Vim(call):E475: Invalid argument: container references itself', eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1',
exc_exec('call msgpackdump([todump])')) exc_exec('call msgpackdump([todump])'))
end) end)

View File

@@ -497,7 +497,7 @@ $
it('errors when a funcref is stored in a variable', function() it('errors when a funcref is stored in a variable', function()
nvim_command('let F = function("tr")') nvim_command('let F = function("tr")')
nvim_command('set shada+=!') nvim_command('set shada+=!')
eq('\nE475: Invalid argument: attempt to dump function reference' eq('\nE951: Error while dumping variable g:F, itself: attempt to dump function reference'
.. '\nE574: Failed to write variable F', .. '\nE574: Failed to write variable F',
redir_exec('wshada')) redir_exec('wshada'))
end) end)
@@ -506,7 +506,7 @@ $
nvim_command('let L = []') nvim_command('let L = []')
nvim_command('call add(L, L)') nvim_command('call add(L, L)')
nvim_command('set shada+=!') nvim_command('set shada+=!')
eq('\nE475: Invalid argument: container references itself' eq('\nE952: Unable to dump variable g:L: container references itself in index 0'
.. '\nE574: Failed to write variable L', .. '\nE574: Failed to write variable L',
redir_exec('wshada')) redir_exec('wshada'))
end) end)

View File

@@ -143,7 +143,7 @@ describe('ShaDa support code', function()
meths.set_var('U', '10') meths.set_var('U', '10')
nvim_command('set shada+=!') nvim_command('set shada+=!')
set_additional_cmd('set shada+=!') set_additional_cmd('set shada+=!')
eq('Vim(wshada):E475: Invalid argument: attempt to dump function reference', eq('Vim(wshada):E951: Error while dumping variable g:F, itself: attempt to dump function reference',
exc_exec('wshada')) exc_exec('wshada'))
meths.set_option('shada', '') meths.set_option('shada', '')
reset() reset()
@@ -156,7 +156,7 @@ describe('ShaDa support code', function()
nvim_command('call add(L, L)') nvim_command('call add(L, L)')
meths.set_var('U', '10') meths.set_var('U', '10')
nvim_command('set shada+=!') nvim_command('set shada+=!')
eq('Vim(wshada):E475: Invalid argument: container references itself', eq('Vim(wshada):E952: Unable to dump variable g:L: container references itself in index 0',
exc_exec('wshada')) exc_exec('wshada'))
meths.set_option('shada', '') meths.set_option('shada', '')
set_additional_cmd('set shada+=!') set_additional_cmd('set shada+=!')