From e2994a3c62265a26a632ed7cd4d11ce4fb711586 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 26 Jul 2015 01:52:50 +0300 Subject: [PATCH] shada,functests: Test how ShaDa support code reacts on errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some notes: - Replaced msgpack_unpacker usage with regular xmalloc’ed buffer. Also since msgpack_unpack_next (as well as msgpack_unpacker_next) is not ever going to return MSGPACK_UNPACK_EXTRA_BYTES this condition was checked manually. Function that does return this status is msgpack_unpack, but it is marked as obsolete. - Zero type is checked prior to main switch in shada_read_next_item because otherwise check would be skipped. - Zeroing entry at the start of shada_read_next_item makes it safer. - dedent('') does not work. - v:oldfiles list is only replaced with bang, if it is NULL or empty. --- src/nvim/shada.c | 126 +++++--- test/functional/helpers.lua | 7 +- test/functional/shada/errors_spec.lua | 399 ++++++++++++++++++++++++++ test/functional/shada/helpers.lua | 19 +- test/functional/shada/marks_spec.lua | 12 +- 5 files changed, 513 insertions(+), 50 deletions(-) create mode 100644 test/functional/shada/errors_spec.lua diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 92a1a11d27..3672e2db25 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1061,8 +1061,11 @@ static inline bool marks_equal(const pos_T a, const pos_T b) static void shada_read(ShaDaReadDef *const sd_reader, const int flags) FUNC_ATTR_NONNULL_ALL { + list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES); const bool force = flags & kShaDaForceit; - const bool get_old_files = flags & (kShaDaGetOldfiles | kShaDaForceit); + const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit) + && (force || oldfiles_list == NULL + || oldfiles_list->lv_len == 0)); const bool want_marks = flags & kShaDaWantMarks; const unsigned srni_flags = ((flags & kShaDaWantInfo ? (kSDReadUndisableableData @@ -1105,11 +1108,12 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) fname_bufs = kh_init(fnamebufs); } khash_t(strset) *oldfiles_set = NULL; - list_T *oldfiles_list = NULL; if (get_old_files) { oldfiles_set = kh_init(strset); - oldfiles_list = list_alloc(); - set_vim_var_list(VV_OLDFILES, oldfiles_list); + if (oldfiles_list == NULL) { + oldfiles_list = list_alloc(); + set_vim_var_list(VV_OLDFILES, oldfiles_list); + } } while (shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0) == NOTDONE) { @@ -3134,7 +3138,11 @@ static int shada_read_next_item(ShaDaReadDef *const sd_reader, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { shada_read_next_item_start: - entry->type = kSDItemMissing; + // Set entry type to kSDItemMissing and also make sure that all pointers in + // data union are NULL so they are safe to xfree(). This is needed in case + // somebody calls goto shada_read_next_item_error before anything is set in + // the switch. + memset(entry, 0, sizeof(*entry)); if (sd_reader->eof) { return OK; } @@ -3162,6 +3170,18 @@ shada_read_next_item_start: const size_t length = (size_t) length_u64; entry->timestamp = (Timestamp) timestamp_u64; + if (type_u64 == 0) { + // kSDItemUnknown cannot possibly pass that far because it is -1 and that + // will fail in msgpack_read_uint64. But kSDItemMissing may and it will + // otherwise be skipped because (1 << 0) will never appear in flags. + emsgu(_(RERR "Error while reading ShaDa file: " + "there is an item at position %" PRIu64 " " + "that must not be there: Missing items are " + "for internal uses only"), + (uint64_t) initial_fpos); + return FAIL; + } + if ((type_u64 > SHADA_LAST_ENTRY ? !(flags & kSDReadUnknown) : !((unsigned) (1 << type_u64) & flags)) @@ -3180,28 +3200,26 @@ shada_read_next_item_start: return fread_len(sd_reader, entry->data.unknown_item.contents, length); } - msgpack_unpacker *const unpacker = msgpack_unpacker_new(length); - if (unpacker == NULL || - !msgpack_unpacker_reserve_buffer(unpacker, length)) { - EMSG(_(e_outofmem)); - goto shada_read_next_item_error; - } + char *const buf = xmalloc(length); - if (fread_len(sd_reader, msgpack_unpacker_buffer(unpacker), length) != OK) { - msgpack_unpacker_free(unpacker); + if (fread_len(sd_reader, buf, length) != OK) { + xfree(buf); return FAIL; } - msgpack_unpacker_buffer_consumed(unpacker, length); msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); bool did_try_to_free = false; shada_read_next_item_read_next: {} + size_t off = 0; const msgpack_unpack_return result = - msgpack_unpacker_next(unpacker, &unpacked); + msgpack_unpack_next(&unpacked, buf, length, &off); switch (result) { case MSGPACK_UNPACK_SUCCESS: { + if (off < length) { + goto shada_read_next_item_extra_bytes; + } break; } case MSGPACK_UNPACK_PARSE_ERROR: { @@ -3226,6 +3244,7 @@ shada_read_next_item_read_next: {} goto shada_read_next_item_error; } case MSGPACK_UNPACK_EXTRA_BYTES: { +shada_read_next_item_extra_bytes: emsgu(_(RERR "Failed to parse ShaDa file: extra bytes in msgpack string " "at position %" PRIu64), (uint64_t) initial_fpos); @@ -3418,23 +3437,47 @@ shada_read_next_item_read_next: {} ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1); for (size_t i = 0; i < unpacked.data.via.map.size; i++) { CHECK_KEY_IS_STR("mark"); - CHECKED_KEY( - "mark", KEY_NAME_CHAR, " which is not an unsigned integer", - entry->data.filemark.name, - (type_u64 != kSDItemJump - && type_u64 != kSDItemChange - && unpacked.data.via.map.ptr[i].val.type - == MSGPACK_OBJECT_POSITIVE_INTEGER), - u64, TOCHAR) - else LONG_KEY("mark", KEY_LNUM, entry->data.filemark.mark.lnum) + if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) { + if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) { + emsgu(_(RERR "Error while reading ShaDa file: " + "mark entry at position %" PRIu64 " " + "has n key which is only valid " + "for local and global mark entries"), + (uint64_t) initial_fpos); + ga_clear(&ad_ga); + goto shada_read_next_item_error; + } + CHECKED_ENTRY( + (unpacked.data.via.map.ptr[i].val.type + == MSGPACK_OBJECT_POSITIVE_INTEGER), + "has n key value which is not an unsigned integer", + "mark", unpacked.data.via.map.ptr[i].val, + entry->data.filemark.name, u64, TOCHAR); + } else LONG_KEY("mark", KEY_LNUM, entry->data.filemark.mark.lnum) else INTEGER_KEY("mark", KEY_COL, entry->data.filemark.mark.col) else STRING_KEY("mark", KEY_FILE, entry->data.filemark.fname) else ADDITIONAL_KEY } - if (entry->data.filemark.mark.lnum == 0) { + if (entry->data.filemark.fname == NULL) { emsgu(_(RERR "Error while reading ShaDa file: " "mark entry at position %" PRIu64 " " - "is missing line number"), + "is missing file name"), + (uint64_t) initial_fpos); + ga_clear(&ad_ga); + goto shada_read_next_item_error; + } + if (entry->data.filemark.mark.lnum <= 0) { + emsgu(_(RERR "Error while reading ShaDa file: " + "mark entry at position %" PRIu64 " " + "has invalid line number"), + (uint64_t) initial_fpos); + ga_clear(&ad_ga); + goto shada_read_next_item_error; + } + if (entry->data.filemark.mark.col < 0) { + emsgu(_(RERR "Error while reading ShaDa file: " + "mark entry at position %" PRIu64 " " + "has invalid column number"), (uint64_t) initial_fpos); ga_clear(&ad_ga); goto shada_read_next_item_error; @@ -3513,7 +3556,7 @@ shada_read_next_item_read_next: {} if (arr.ptr[i].type != MSGPACK_OBJECT_BIN) { emsgu(_(RERR "Error while reading ShaDa file: " "register entry at position %" PRIu64 " " - "has " REG_KEY_CONTENTS " array with non-string value"), + "has " REG_KEY_CONTENTS " array with non-binary value"), (uint64_t) initial_fpos); ga_clear(&ad_ga); goto shada_read_next_item_error; @@ -3851,6 +3894,22 @@ shada_read_next_item_hist_no_conv: } } } + if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) { + emsgu(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " " + "contains entry with invalid line number"), + (uint64_t) initial_fpos); + ga_clear(&ad_ga); + goto shada_read_next_item_error; + } + if (entry->data.buffer_list.buffers[i].pos.col < 0) { + emsgu(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " " + "contains entry with invalid column number"), + (uint64_t) initial_fpos); + ga_clear(&ad_ga); + goto shada_read_next_item_error; + } if (entry->data.buffer_list.buffers[i].fname == NULL) { emsgu(_(RERR "Error while reading ShaDa file: " "buffer list at position %" PRIu64 " " @@ -3887,14 +3946,7 @@ shada_read_next_item_hist_no_conv: } break; } - case kSDItemMissing: { - emsgu(_(RERR "Error while reading ShaDa file: " - "there is an item at position %" PRIu64 " " - "that must not be there: Missing items are " - "for internal uses only"), - (uint64_t) initial_fpos); - goto shada_read_next_item_error; - } + case kSDItemMissing: case kSDItemUnknown: { assert(false); } @@ -3921,14 +3973,14 @@ shada_read_next_item_hist_no_conv: #undef TOSIZE shada_read_next_item_error: msgpack_unpacked_destroy(&unpacked); - msgpack_unpacker_free(unpacker); + xfree(buf); entry->type = (ShadaEntryType) type_u64; shada_free_shada_entry(entry); entry->type = kSDItemMissing; return FAIL; shada_read_next_item_end: msgpack_unpacked_destroy(&unpacked); - msgpack_unpacker_free(unpacker); + xfree(buf); return NOTDONE; } diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index a6f4f7c2e5..23581ba4d2 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -220,9 +220,12 @@ local function execute(...) end -- Dedent the given text and write it to the file name. -local function write_file(name, text) +local function write_file(name, text, dont_dedent) local file = io.open(name, 'w') - file:write(dedent(text)) + if not dont_dedent then + text = dedent(text) + end + file:write(text) file:flush() file:close() end diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua new file mode 100644 index 0000000000..5107273115 --- /dev/null +++ b/test/functional/shada/errors_spec.lua @@ -0,0 +1,399 @@ +-- ShaDa errors handling support +local helpers = require('test.functional.helpers') +local nvim, nvim_window, nvim_curwin, nvim_command, nvim_feed, nvim_eval, eq = + helpers.nvim, helpers.window, helpers.curwin, helpers.command, helpers.feed, + helpers.eval, helpers.eq +local write_file = helpers.write_file + +local shada_helpers = require('test.functional.shada.helpers') +local reset, set_additional_cmd, clear, exc_exec = + shada_helpers.reset, shada_helpers.set_additional_cmd, + shada_helpers.clear, shada_helpers.exc_exec + +local shada_fname = 'Xtest-functional-shada-errors.shada' +local wshada = function(text) + write_file(shada_fname, text, true) +end +local sdrcmd = function(bang) + return 'rshada' .. (bang and '!' or '') .. ' ' .. shada_fname +end + +describe('ShaDa error handling', function() + before_each(reset) + after_each(function() + clear() + os.remove(shada_fname) + local i = ('a'):byte() + while i < ('z'):byte() do + if not os.remove(shada_fname .. ('.tmp.%c'):format(i)) then + break + end + i = i + 1 + end + end) + + -- Note: most of tests have additional items like sX, mX, rX. These are for + -- valgrind tests, to check for memory leaks (i.e. whether error handling code + -- does (not) forget to call ga_clear). Not needed for array-based items like + -- history because they are not using ad_ga. + + it('does not fail on empty file', function() + wshada('') + eq(0, exc_exec(sdrcmd())) + end) + + it('fails on zero', function() + wshada('\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', exc_exec(sdrcmd())) + end) + + it('fails on missing item', function() + wshada('\000\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: there is an item at position 0 that must not be there: Missing items are for internal uses only', exc_exec(sdrcmd())) + end) + + it('fails on -2 type', function() + wshada('\254\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 0', exc_exec(sdrcmd())) + end) + + it('does not fail on header with zero length', function() + -- Header items are skipped when reading. + wshada('\001\000\000') + eq(0, exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with zero length', function() + wshada('\002\000\000') + eq('Vim(rshada):E575: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with -2 timestamp', function() + wshada('\002\254\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 1', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with -2 length', function() + wshada('\002\000\254') + eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 2', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with length greater then file length', function() + wshada('\002\000\002\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: last entry specified that it occupies 2 bytes, but file ended earlier', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with invalid byte', function() + -- 195 (== 0xC1) cannot start any valid messagepack entry (the only byte + -- that cannot do this). Specifically unpack_template.h contains + -- + -- //case 0xc1: // string + -- // again_terminal_trail(NEXT_CS(p), p+1); + -- + -- (literally: commented out code) which means that in place of this code + -- `goto _failed` is used from default: case. I do not know any other way to + -- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or + -- MSGPACK_UNPACK_EXTRA_BYTES. + wshada('\002\000\001\193') + eq('Vim(rshada):E575: Failed to parse ShaDa file due to a msgpack parser error at position 0', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with incomplete map', function() + wshada('\002\000\001\129') + eq('Vim(rshada):E575: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item without a pattern', function() + wshada('\002\000\005\129\162sX\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has no pattern', exc_exec(sdrcmd())) + end) + + it('fails on search pattern with extra bytes', function() + wshada('\002\000\002\128\000') + eq('Vim(rshada):E575: Failed to parse ShaDa file: extra bytes in msgpack string at position 0', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL value', function() + wshada('\002\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', exc_exec(sdrcmd())) + end) + + -- sp entry is here because it causes an allocation. + it('fails on search pattern item with BIN key', function() + wshada('\002\000\014\131\162sp\196\001a\162sX\192\196\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key which is not a string', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL magic key value', function() + wshada('\002\000\009\130\162sX\192\162sm\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sm key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL smartcase key value', function() + wshada('\002\000\009\130\162sX\192\162sc\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sc key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL has_line_offset key value', function() + wshada('\002\000\009\130\162sX\192\162sl\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sl key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL place_cursor_at_end key value', function() + wshada('\002\000\009\130\162sX\192\162se\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has se key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL is_last_used key value', function() + wshada('\002\000\009\130\162sX\192\162su\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has su key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL is_substitute_pattern key value', function() + wshada('\002\000\009\130\162sX\192\162ss\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has ss key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL highlighted key value', function() + wshada('\002\000\009\130\162sX\192\162sh\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sh key value which is not a boolean', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL offset key value', function() + wshada('\002\000\009\130\162sX\192\162so\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has so key value which is not an integer', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with NIL pat key value', function() + wshada('\002\000\009\130\162sX\192\162sp\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary', exc_exec(sdrcmd())) + end) + + it('fails on search pattern item with STR pat key value', function() + wshada('\002\000\011\130\162sX\192\162sp\162sp') + eq('Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary', exc_exec(sdrcmd())) + end) + + for _, v in ipairs({{name='global mark', mpack='\007'}, + {name='jump', mpack='\008'}, + {name='local mark', mpack='\010'}, + {name='change', mpack='\011'}, + }) do + local is_mark_test = ({['global mark']=true, ['local mark']=true})[v.name] + + it('fails on ' .. v.name .. ' item with NIL value', function() + wshada(v.mpack .. '\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dictionary', exc_exec(sdrcmd())) + end) + + -- f entry is here because it causes an allocation. + it('fails on ' .. v.name .. ' item with BIN key', function() + wshada(v.mpack .. '\000\013\131\161f\196\001/\162mX\192\196\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has key which is not a string', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item without f key', function() + wshada(v.mpack .. '\000\008\130\162mX\192\161l\001') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is missing file name', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with zero l key', function() + wshada(v.mpack .. '\000\013\131\162mX\192\161f\196\001/\161l\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has invalid line number', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with negative l key', function() + wshada(v.mpack .. '\000\013\131\162mX\192\161f\196\001/\161l\255') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has invalid line number', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with negative c key', function() + wshada(v.mpack .. '\000\013\131\162mX\192\161f\196\001/\161c\255') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has invalid column number', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with STR n key value', function() + wshada(v.mpack .. '\000\011\130\162mX\192\161n\163spa') + eq(is_mark_test and 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an unsigned integer' or 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key which is only valid for local and global mark entries', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with STR l key value', function() + wshada(v.mpack .. '\000\010\130\162mX\192\161l\162sp') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has l key value which is not an integer', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with STR c key value', function() + wshada(v.mpack .. '\000\010\130\162mX\192\161c\162sp') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has c key value which is not an integer', exc_exec(sdrcmd())) + end) + + it('fails on ' .. v.name .. ' item with STR f key value', function() + wshada(v.mpack .. '\000\010\130\162mX\192\161f\162sp') + eq('Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has f key value which is not a binary', exc_exec(sdrcmd())) + end) + end + + it('fails on register item with NIL value', function() + wshada('\005\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dictionary', exc_exec(sdrcmd())) + end) + + -- rc entry is here because it causes an allocation + it('fails on register item with BIN key', function() + wshada('\005\000\015\131\162rc\145\196\001a\162rX\192\196\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has key which is not a string', exc_exec(sdrcmd())) + end) + + it('fails on register item with NIL rt key value', function() + wshada('\005\000\009\130\162rX\192\162rt\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an unsigned integer', exc_exec(sdrcmd())) + end) + + it('fails on register item with NIL rw key value', function() + wshada('\005\000\009\130\162rX\192\162rw\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an unsigned integer', exc_exec(sdrcmd())) + end) + + it('fails on register item with NIL rc key value', function() + wshada('\005\000\009\130\162rX\192\162rc\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with non-array value', exc_exec(sdrcmd())) + end) + + it('fails on register item with empty rc key value', function() + wshada('\005\000\009\130\162rX\192\162rc\144') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with empty array', exc_exec(sdrcmd())) + end) + + it('fails on register item with NIL in rc array', function() + wshada('\005\000\013\130\162rX\192\162rc\146\196\001a\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc array with non-binary value', exc_exec(sdrcmd())) + end) + + it('fails on register item without rc array', function() + wshada('\005\000\009\129\162rX\146\196\001a\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has missing rc array', exc_exec(sdrcmd())) + end) + + it('fails on history item with NIL value', function() + wshada('\004\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array', exc_exec(sdrcmd())) + end) + + it('fails on history item with empty value', function() + wshada('\004\000\001\144') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', exc_exec(sdrcmd())) + end) + + it('fails on history item with single element value', function() + wshada('\004\000\002\145\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', exc_exec(sdrcmd())) + end) + + it('fails on history item with NIL first item', function() + wshada('\004\000\003\146\192\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 has wrong history type type', exc_exec(sdrcmd())) + end) + + it('fails on history item with FIXUINT second item', function() + wshada('\004\000\003\146\000\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 has wrong history string type', exc_exec(sdrcmd())) + end) + + it('fails on history item with second item with zero byte', function() + wshada('\004\000\007\146\000\196\003ab\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 contains string with zero byte inside', exc_exec(sdrcmd())) + end) + + it('fails on search history item without third item', function() + wshada('\004\000\007\146\001\196\003abc') + eq('Vim(rshada):E575: Error while reading ShaDa file: search history entry at position 0 does not have separator character', exc_exec(sdrcmd())) + end) + + it('fails on search history item with NIL third item', function() + wshada('\004\000\007\147\001\196\002ab\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: search history entry at position 0 has wrong history separator type', exc_exec(sdrcmd())) + end) + + it('fails on variable item with NIL value', function() + wshada('\006\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array', exc_exec(sdrcmd())) + end) + + it('fails on variable item with empty value', function() + wshada('\006\000\001\144') + eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', exc_exec(sdrcmd())) + end) + + it('fails on variable item with single element value', function() + wshada('\006\000\002\145\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', exc_exec(sdrcmd())) + end) + + it('fails on variable item with NIL first item', function() + wshada('\006\000\003\146\192\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 has wrong variable name type', exc_exec(sdrcmd())) + end) + + it('fails on replacement item with NIL value', function() + wshada('\003\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array', exc_exec(sdrcmd())) + end) + + it('fails on replacement item with empty value', function() + wshada('\003\000\001\144') + eq('Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 does not have enough elements', exc_exec(sdrcmd())) + end) + + it('fails on replacement item with NIL first item', function() + wshada('\003\000\002\145\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 has wrong sub string type', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with NIL value', function() + nvim_command('set shada+=%') + wshada('\009\000\001\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list entry at position 0 is not an array', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with NIL item in the array', function() + nvim_command('set shada+=%') + wshada('\009\000\008\146\129\161f\196\001/\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dictionary', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with empty item', function() + nvim_command('set shada+=%') + wshada('\009\000\008\146\129\161f\196\001/\128') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that does not have a file name', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with NIL l key', function() + nvim_command('set shada+=%') + wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has l key value which is not an integer', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with zero l key', function() + nvim_command('set shada+=%') + wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\000') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry with invalid line number', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with negative l key', function() + nvim_command('set shada+=%') + wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\255') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry with invalid line number', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with negative c key', function() + nvim_command('set shada+=%') + wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\255') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry with invalid column number', exc_exec(sdrcmd())) + end) + + it('fails on buffer list item with NIL c key', function() + nvim_command('set shada+=%') + wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\192') + eq('Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has c key value which is not an integer', exc_exec(sdrcmd())) + end) +end) diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua index 7e93fcb915..909fcd62e6 100644 --- a/test/functional/shada/helpers.lua +++ b/test/functional/shada/helpers.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers') -local spawn, set_session, nvim, nvim_prog = - helpers.spawn, helpers.set_session, helpers.nvim, helpers.nvim_prog +local spawn, set_session, nvim, nvim_prog, nvim_command, nvim_eval = + helpers.spawn, helpers.set_session, helpers.nvim, helpers.nvim_prog, + helpers.command, helpers.eval local tmpname = os.tmpname() local additional_cmd = '' @@ -46,8 +47,22 @@ local clear = function() set_additional_cmd('') end +local exc_exec = function(cmd) + nvim_command(([[ + try + execute "%s" + catch + let g:__exception = v:exception + endtry + ]]):format(cmd:gsub('\n', '\\n'):gsub('[\\"]', '\\%0'))) + local ret = nvim_eval('get(g:, "__exception", 0)') + nvim_command('unlet! g:__exception') + return ret +end + return { reset=reset, set_additional_cmd=set_additional_cmd, clear=clear, + exc_exec=exc_exec, } diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index 4909ae608e..341ca2d647 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -5,9 +5,9 @@ local nvim, nvim_window, nvim_curwin, nvim_command, nvim_feed, nvim_eval, eq = helpers.eval, helpers.eq local shada_helpers = require('test.functional.shada.helpers') -local reset, set_additional_cmd, clear = +local reset, set_additional_cmd, clear, exc_exec = shada_helpers.reset, shada_helpers.set_additional_cmd, - shada_helpers.clear + shada_helpers.clear, shada_helpers.exc_exec local nvim_current_line = function() return nvim_window('get_cursor', nvim_curwin())[1] @@ -57,13 +57,7 @@ describe('ShaDa support code', function() nvim_command('wshada') reset() nvim_command('language C') - nvim_command([[ - try - execute "normal! `A" - catch - let exception = v:exception - endtry]]) - eq('Vim(normal):E20: Mark not set', nvim('get_var', 'exception')) + eq('Vim(normal):E20: Mark not set', exc_exec('normal! `A')) end) it('does read back global mark even with `\'0` and `f0` in shada', function()