diff options
| -rw-r--r-- | src/nvim/eval/typval.c | 32 | ||||
| -rw-r--r-- | test/unit/eval/typval_spec.lua | 116 | 
2 files changed, 132 insertions, 16 deletions
| diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 867330c137..d9feb2d88e 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1009,18 +1009,6 @@ void tv_dict_item_free(dictitem_T *const item)    }  } -/// Add item to dictionary -/// -/// @param[out]  d  Dictionary to add to. -/// @param[in]  item  Item to add. -/// -/// @return FAIL if key already exists. -int tv_dict_add(dict_T *const d, dictitem_T *const item) -  FUNC_ATTR_NONNULL_ALL -{ -  return hash_add(&d->dv_hashtab, item->di_key); -} -  /// Make a copy of a dictionary item  ///  /// @param[in]  di  Item to copy. @@ -1278,6 +1266,18 @@ bool tv_dict_get_callback(dict_T *const d,  //{{{2 dict_add* +/// Add item to dictionary +/// +/// @param[out]  d  Dictionary to add to. +/// @param[in]  item  Item to add. +/// +/// @return FAIL if key already exists. +int tv_dict_add(dict_T *const d, dictitem_T *const item) +  FUNC_ATTR_NONNULL_ALL +{ +  return hash_add(&d->dv_hashtab, item->di_key); +} +  /// Add a list entry to dictionary  ///  /// @param[out]  d  Dictionary to add entry to. @@ -1295,11 +1295,11 @@ int tv_dict_add_list(dict_T *const d, const char *const key,    item->di_tv.v_lock = VAR_UNLOCKED;    item->di_tv.v_type = VAR_LIST;    item->di_tv.vval.v_list = list; +  list->lv_refcount++;    if (tv_dict_add(d, item) == FAIL) {      tv_dict_item_free(item);      return FAIL;    } -  list->lv_refcount++;    return OK;  } @@ -1313,18 +1313,18 @@ int tv_dict_add_list(dict_T *const d, const char *const key,  /// @return OK in case of success, FAIL when key already exists.  int tv_dict_add_dict(dict_T *const d, const char *const key,                       const size_t key_len, dict_T *const dict) -    FUNC_ATTR_NONNULL_ALL +  FUNC_ATTR_NONNULL_ALL  { -  dictitem_T *const item = tv_dict_item_alloc(key); +  dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);    item->di_tv.v_lock = VAR_UNLOCKED;    item->di_tv.v_type = VAR_DICT;    item->di_tv.vval.v_dict = dict; +  dict->dv_refcount++;    if (tv_dict_add(d, item) == FAIL) {      tv_dict_item_free(item);      return FAIL;    } -  dict->dv_refcount++;    return OK;  } diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index d91fd3e78d..c710171779 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -1770,6 +1770,122 @@ describe('typval.c', function()               {tv_dict_get_callback(d, 'testt', 5)})          end)        end) +      describe('dict_add()', function() +        itp('works', function() +          local di = lib.tv_dict_item_alloc_len('t-est', 5) +          alloc_log:check({a.di(di, 't-est')}) +          di.di_tv.v_type = lib.VAR_NUMBER +          di.di_tv.vval.v_number = 42 +          local d = dict({test=10}) +          local dis = dict_items(d) +          alloc_log:check({ +            a.dict(d), +            a.di(dis.test, 'test') +          }) +          eq({test=10}, dct2tbl(d)) +          alloc_log:clear() +          eq(OK, lib.tv_dict_add(d, di)) +          alloc_log:check({}) +          eq({test=10, ['t-est']=int(42)}, dct2tbl(d)) +          eq(FAIL, check_emsg(function() return lib.tv_dict_add(d, di) end, +                              'E685: Internal error: hash_add()')) +        end) +      end) +      describe('dict_add_list()', function() +        itp('works', function() +          local l = list(1, 2, 3) +          alloc_log:clear() +          eq(1, l.lv_refcount) +          local d = dict({test=10}) +          alloc_log:clear() +          eq({test=10}, dct2tbl(d)) +          eq(OK, lib.tv_dict_add_list(d, 'testt', 3, l)) +          local dis = dict_items(d) +          alloc_log:check({a.di(dis.tes, 'tes')}) +          eq({test=10, tes={1, 2, 3}}, dct2tbl(d)) +          eq(2, l.lv_refcount) +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_list(d, 'testt', 3, l) end, +                              'E685: Internal error: hash_add()')) +          eq(2, l.lv_refcount) +          alloc_log:clear() +          lib.emsg_skip = lib.emsg_skip + 1 +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_list(d, 'testt', 3, l) end, +                              nil)) +          eq(2, l.lv_refcount) +          lib.emsg_skip = lib.emsg_skip - 1 +          alloc_log:clear_tmp_allocs() +          alloc_log:check({}) +        end) +      end) +      describe('dict_add_dict()', function() +        itp('works', function() +          local d2 = dict({foo=42}) +          alloc_log:clear() +          eq(1, d2.dv_refcount) +          local d = dict({test=10}) +          alloc_log:clear() +          eq({test=10}, dct2tbl(d)) +          eq(OK, lib.tv_dict_add_dict(d, 'testt', 3, d2)) +          local dis = dict_items(d) +          alloc_log:check({a.di(dis.tes, 'tes')}) +          eq({test=10, tes={foo=42}}, dct2tbl(d)) +          eq(2, d2.dv_refcount) +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_dict(d, 'testt', 3, d2) end, +                              'E685: Internal error: hash_add()')) +          eq(2, d2.dv_refcount) +          alloc_log:clear() +          lib.emsg_skip = lib.emsg_skip + 1 +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_dict(d, 'testt', 3, d2) end, +                              nil)) +          eq(2, d2.dv_refcount) +          lib.emsg_skip = lib.emsg_skip - 1 +          alloc_log:clear_tmp_allocs() +          alloc_log:check({}) +        end) +      end) +      describe('dict_add_nr()', function() +        itp('works', function() +          local d = dict({test=10}) +          alloc_log:clear() +          eq({test=10}, dct2tbl(d)) +          eq(OK, lib.tv_dict_add_nr(d, 'testt', 3, 2)) +          local dis = dict_items(d) +          alloc_log:check({a.di(dis.tes, 'tes')}) +          eq({test=10, tes=int(2)}, dct2tbl(d)) +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_nr(d, 'testt', 3, 2) end, +                              'E685: Internal error: hash_add()')) +          alloc_log:clear() +          lib.emsg_skip = lib.emsg_skip + 1 +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_nr(d, 'testt', 3, 2) end, +                              nil)) +          lib.emsg_skip = lib.emsg_skip - 1 +          alloc_log:clear_tmp_allocs() +          alloc_log:check({}) +        end) +      end) +      describe('dict_add_str()', function() +        itp('works', function() +          local d = dict({test=10}) +          alloc_log:clear() +          eq({test=10}, dct2tbl(d)) +          eq(OK, lib.tv_dict_add_str(d, 'testt', 3, 'TEST')) +          local dis = dict_items(d) +          alloc_log:check({ +            a.di(dis.tes, 'tes'), +            a.str(dis.tes.di_tv.vval.v_string, 'TEST') +          }) +          eq({test=10, tes='TEST'}, dct2tbl(d)) +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_str(d, 'testt', 3, 'TEST') end, +                              'E685: Internal error: hash_add()')) +          alloc_log:clear() +          lib.emsg_skip = lib.emsg_skip + 1 +          eq(FAIL, check_emsg(function() return lib.tv_dict_add_str(d, 'testt', 3, 'TEST') end, +                              nil)) +          lib.emsg_skip = lib.emsg_skip - 1 +          alloc_log:clear_tmp_allocs() +          alloc_log:check({}) +        end) +      end)      end)    end)  end) | 
