aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2016-09-19 00:50:07 +0300
committerZyX <kp-pav@yandex.ru>2017-03-29 10:08:06 +0300
commit56e4c2f67e54b88f637d30e565313bc6b2c22f29 (patch)
treef1a4c2e4f1f8c6dc8787c04f0240319e72d9ac65
parentf80a00469fdba8a3dec0edae30c911d050485055 (diff)
downloadrneovim-56e4c2f67e54b88f637d30e565313bc6b2c22f29.tar.gz
rneovim-56e4c2f67e54b88f637d30e565313bc6b2c22f29.tar.bz2
rneovim-56e4c2f67e54b88f637d30e565313bc6b2c22f29.zip
unittests: Test tv_list_concat()
-rw-r--r--src/nvim/eval/typval.c2
-rw-r--r--test/unit/eval/typval_spec.lua142
2 files changed, 143 insertions, 1 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 9dd1b62d7d..1cc195ddc4 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -481,7 +481,7 @@ void tv_list_extend(list_T *const l1, list_T *const l2,
int todo = l2->lv_len;
// We also quit the loop when we have inserted the original item count of
// the list, avoid a hang when we extend a list with itself.
- for (listitem_T *item = l2->lv_first
+ for (listitem_T *item = l2->lv_first
; item != NULL && --todo >= 0
; item = item->li_next) {
tv_list_insert_tv(l1, &item->li_tv, bef);
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index 7a6b4579f9..2cc22053f3 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -14,6 +14,7 @@ local alloc_log_new = helpers.alloc_log_new
local a = eval_helpers.alloc_logging_helpers
local list = eval_helpers.list
local lst2tbl = eval_helpers.lst2tbl
+local typvalt = eval_helpers.typvalt
local type_key = eval_helpers.type_key
local li_alloc = eval_helpers.li_alloc
local int_type = eval_helpers.int_type
@@ -747,5 +748,146 @@ describe('typval.c', function()
eq(1, l_copy1.lv_refcount)
end)
end)
+ describe('concat()', function()
+ itp('works with NULL lists', function()
+ local l = list(1, {})
+ alloc_log:clear()
+ eq(1, l.lv_refcount)
+ eq(1, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+
+ local rettv1 = typvalt()
+ eq(OK, lib.tv_list_concat(nil, l, rettv1))
+ eq(1, l.lv_refcount)
+ eq(tonumber(lib.VAR_LIST), tonumber(rettv1.v_type))
+ eq({1, {}}, typvalt2lua(rettv1))
+ eq(1, rettv1.vval.v_list.lv_refcount)
+ alloc_log:check({
+ a.list(rettv1.vval.v_list),
+ a.li(rettv1.vval.v_list.lv_first),
+ a.li(rettv1.vval.v_list.lv_last),
+ })
+ eq(2, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+
+ local rettv2 = typvalt()
+ eq(OK, lib.tv_list_concat(l, nil, rettv2))
+ eq(1, l.lv_refcount)
+ eq(tonumber(lib.VAR_LIST), tonumber(rettv2.v_type))
+ eq({1, {}}, typvalt2lua(rettv2))
+ eq(1, rettv2.vval.v_list.lv_refcount)
+ alloc_log:check({
+ a.list(rettv2.vval.v_list),
+ a.li(rettv2.vval.v_list.lv_first),
+ a.li(rettv2.vval.v_list.lv_last),
+ })
+ eq(3, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+
+ local rettv3 = typvalt()
+ eq(OK, lib.tv_list_concat(nil, nil, rettv3))
+ eq(tonumber(lib.VAR_LIST), tonumber(rettv3.v_type))
+ eq(null_list, typvalt2lua(rettv3))
+ alloc_log:check({})
+ end)
+ itp('works with two different lists', function()
+ local l1 = list(1, {})
+ local l2 = list(3, {[type_key]=list_type})
+ eq(1, l1.lv_refcount)
+ eq(1, l1.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, l2.lv_refcount)
+ eq(1, l2.lv_last.li_tv.vval.v_list.lv_refcount)
+ alloc_log:clear()
+
+ local rettv = typvalt()
+ eq(OK, lib.tv_list_concat(l1, l2, rettv))
+ eq(1, l1.lv_refcount)
+ eq(2, l1.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, l2.lv_refcount)
+ eq(2, l2.lv_last.li_tv.vval.v_list.lv_refcount)
+ alloc_log:check({
+ a.list(rettv.vval.v_list),
+ a.li(rettv.vval.v_list.lv_first),
+ a.li(rettv.vval.v_list.lv_first.li_next),
+ a.li(rettv.vval.v_list.lv_last.li_prev),
+ a.li(rettv.vval.v_list.lv_last),
+ })
+ eq({1, {}, 3, {[type_key]=list_type}}, typvalt2lua(rettv))
+ end)
+ itp('can concatenate list with itself', function()
+ local l = list(1, {})
+ eq(1, l.lv_refcount)
+ eq(1, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ alloc_log:clear()
+
+ local rettv = typvalt()
+ eq(OK, lib.tv_list_concat(l, l, rettv))
+ eq(1, l.lv_refcount)
+ eq(3, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ alloc_log:check({
+ a.list(rettv.vval.v_list),
+ a.li(rettv.vval.v_list.lv_first),
+ a.li(rettv.vval.v_list.lv_first.li_next),
+ a.li(rettv.vval.v_list.lv_last.li_prev),
+ a.li(rettv.vval.v_list.lv_last),
+ })
+ eq({1, {}, 1, {}}, typvalt2lua(rettv))
+ end)
+ itp('can concatenate empty non-NULL lists', function()
+ local l = list(1, {})
+ local le = list()
+ local le2 = list()
+ eq(1, l.lv_refcount)
+ eq(1, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, le.lv_refcount)
+ eq(1, le2.lv_refcount)
+ alloc_log:clear()
+
+ local rettv1 = typvalt()
+ eq(OK, lib.tv_list_concat(l, le, rettv1))
+ eq(1, l.lv_refcount)
+ eq(2, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, le.lv_refcount)
+ eq(1, le2.lv_refcount)
+ alloc_log:check({
+ a.list(rettv1.vval.v_list),
+ a.li(rettv1.vval.v_list.lv_first),
+ a.li(rettv1.vval.v_list.lv_last),
+ })
+ eq({1, {}}, typvalt2lua(rettv1))
+
+ local rettv2 = typvalt()
+ eq(OK, lib.tv_list_concat(le, l, rettv2))
+ eq(1, l.lv_refcount)
+ eq(3, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, le.lv_refcount)
+ eq(1, le2.lv_refcount)
+ alloc_log:check({
+ a.list(rettv2.vval.v_list),
+ a.li(rettv2.vval.v_list.lv_first),
+ a.li(rettv2.vval.v_list.lv_last),
+ })
+ eq({1, {}}, typvalt2lua(rettv2))
+
+ local rettv3 = typvalt()
+ eq(OK, lib.tv_list_concat(le, le, rettv3))
+ eq(1, l.lv_refcount)
+ eq(3, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, le.lv_refcount)
+ eq(1, le2.lv_refcount)
+ alloc_log:check({
+ a.list(rettv3.vval.v_list),
+ })
+ eq({[type_key]=list_type}, typvalt2lua(rettv3))
+
+ local rettv4 = typvalt()
+ eq(OK, lib.tv_list_concat(le, le2, rettv4))
+ eq(1, l.lv_refcount)
+ eq(3, l.lv_last.li_tv.vval.v_dict.dv_refcount)
+ eq(1, le.lv_refcount)
+ eq(1, le2.lv_refcount)
+ alloc_log:check({
+ a.list(rettv4.vval.v_list),
+ })
+ eq({[type_key]=list_type}, typvalt2lua(rettv4))
+ end)
+ end)
end)
end)