aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-03-13 14:35:53 +0300
committerZyX <kp-pav@yandex.ru>2017-03-29 10:08:45 +0300
commit8b9a1fbf7a630b68b1428a39f25e1fa38fe0cc9f (patch)
tree97377c62e6c3fe928dee87ddc8486be28c1ea9ae
parentfa852e7cdc365b6fcd39d677f4067963274c44c3 (diff)
downloadrneovim-8b9a1fbf7a630b68b1428a39f25e1fa38fe0cc9f.tar.gz
rneovim-8b9a1fbf7a630b68b1428a39f25e1fa38fe0cc9f.tar.bz2
rneovim-8b9a1fbf7a630b68b1428a39f25e1fa38fe0cc9f.zip
unittests: Add tests for tv_dict_extend
-rw-r--r--test/unit/eval/helpers.lua12
-rw-r--r--test/unit/eval/tricks_spec.lua14
-rw-r--r--test/unit/eval/typval_spec.lua129
3 files changed, 144 insertions, 11 deletions
diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua
index 6909953022..a3cb062b7b 100644
--- a/test/unit/eval/helpers.lua
+++ b/test/unit/eval/helpers.lua
@@ -498,6 +498,16 @@ local function dict_watchers(d)
return ret, qs, key_patterns
end
+local function eval0(expr)
+ local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
+ eval.tv_clear)
+ if eval.eval0(to_cstr(expr), tv, nil, true) == 0 then
+ return nil
+ else
+ return tv
+ end
+end
+
return {
int=int,
@@ -540,5 +550,7 @@ return {
tbl2callback=tbl2callback,
callback2tbl=callback2tbl,
+ eval0=eval0,
+
empty_list = {[type_key]=list_type},
}
diff --git a/test/unit/eval/tricks_spec.lua b/test/unit/eval/tricks_spec.lua
index 54029734fb..ae569bed11 100644
--- a/test/unit/eval/tricks_spec.lua
+++ b/test/unit/eval/tricks_spec.lua
@@ -1,4 +1,6 @@
local helpers = require('test.unit.helpers')(after_each)
+local eval_helpers = require('test.unit.eval.helpers')
+
local itp = helpers.gen_itp(it)
local cimport = helpers.cimport
@@ -6,19 +8,11 @@ local to_cstr = helpers.to_cstr
local ffi = helpers.ffi
local eq = helpers.eq
+local eval0 = eval_helpers.eval0
+
local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h',
'./src/nvim/memory.h')
-local eval0 = function(expr)
- local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
- eval.tv_clear)
- if eval.eval0(to_cstr(expr), tv, nil, true) == 0 then
- return nil
- else
- return tv
- end
-end
-
describe('NULL typval_T', function()
itp('is produced by $XXX_UNEXISTENT_VAR_XXX', function()
-- Required for various tests which need to check whether typval_T with NULL
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index b16e118053..00dc230e89 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -1,6 +1,7 @@
+local bit = require('bit')
local helpers = require('test.unit.helpers')(after_each)
-local global_helpers = require('test.helpers')
local eval_helpers = require('test.unit.eval.helpers')
+local global_helpers = require('test.helpers')
local itp = helpers.gen_itp(it)
@@ -17,6 +18,7 @@ local a = eval_helpers.alloc_logging_helpers
local int = eval_helpers.int
local list = eval_helpers.list
local dict = eval_helpers.dict
+local eval0 = eval_helpers.eval0
local lst2tbl = eval_helpers.lst2tbl
local dct2tbl = eval_helpers.dct2tbl
local typvalt = eval_helpers.typvalt
@@ -1905,5 +1907,130 @@ describe('typval.c', function()
eq({}, dct2tbl(d))
end)
end)
+ describe('extend()', function()
+ local function tv_dict_extend(d1, d2, action, emsg)
+ action = action or "force"
+ check_emsg(function() return lib.tv_dict_extend(d1, d2, action) end, emsg)
+ end
+ itp('works', function()
+ local d1 = dict()
+ alloc_log:check({a.dict(d1)})
+ eq({}, dct2tbl(d1))
+ local d2 = dict()
+ alloc_log:check({a.dict(d2)})
+ eq({}, dct2tbl(d2))
+ tv_dict_extend(d1, d2, 'error')
+ tv_dict_extend(d1, d2, 'keep')
+ tv_dict_extend(d1, d2, 'force')
+ alloc_log:check({})
+
+ d1 = dict({a='TEST'})
+ eq({a='TEST'}, dct2tbl(d1))
+ local dis1 = dict_items(d1)
+ local a1_s = dis1.a.di_tv.vval.v_string
+ alloc_log:clear_tmp_allocs()
+ alloc_log:check({
+ a.dict(d1),
+ a.di(dis1.a),
+ a.str(a1_s),
+ })
+ d2 = dict({a='TSET'})
+ eq({a='TSET'}, dct2tbl(d2))
+ local dis2 = dict_items(d2)
+ local a2_s = dis2.a.di_tv.vval.v_string
+ alloc_log:clear_tmp_allocs()
+ alloc_log:check({
+ a.dict(d2),
+ a.di(dis2.a),
+ a.str(a2_s),
+ })
+
+ tv_dict_extend(d1, d2, 'error', 'E737: Key already exists: a')
+ eq({a='TEST'}, dct2tbl(d1))
+ eq({a='TSET'}, dct2tbl(d2))
+ alloc_log:clear()
+
+ tv_dict_extend(d1, d2, 'keep')
+ alloc_log:check({})
+ eq({a='TEST'}, dct2tbl(d1))
+ eq({a='TSET'}, dct2tbl(d2))
+
+ tv_dict_extend(d1, d2, 'force')
+ alloc_log:check({
+ a.freed(a1_s),
+ a.str(dis1.a.di_tv.vval.v_string),
+ })
+ eq({a='TSET'}, dct2tbl(d1))
+ eq({a='TSET'}, dct2tbl(d2))
+ end)
+ itp('disallows overriding builtin or user functions', function()
+ local d = dict()
+ d.dv_scope = lib.VAR_DEF_SCOPE
+ local f_lua = {
+ [type_key]=func_type,
+ value='tr',
+ }
+ local f_tv = lua2typvalt(f_lua)
+ local p_lua = {
+ [type_key]=func_type,
+ value='tr',
+ args={1},
+ }
+ local p_tv = lua2typvalt(p_lua)
+ eq(lib.VAR_PARTIAL, p_tv.v_type)
+ local d2 = dict({tr=f_tv})
+ local d3 = dict({tr=p_tv})
+ local d4 = dict({['TEST:THIS']=p_tv})
+ local d5 = dict({Test=f_tv})
+ local d6 = dict({Test=p_tv})
+ eval0([[execute("function Test()\nendfunction")]])
+ tv_dict_extend(d, d2, 'force',
+ 'E704: Funcref variable name must start with a capital: tr')
+ tv_dict_extend(d, d3, 'force',
+ 'E704: Funcref variable name must start with a capital: tr')
+ tv_dict_extend(d, d4, 'force',
+ 'E461: Illegal variable name: TEST:THIS')
+ tv_dict_extend(d, d5, 'force',
+ 'E705: Variable name conflicts with existing function: Test')
+ tv_dict_extend(d, d6, 'force',
+ 'E705: Variable name conflicts with existing function: Test')
+ eq({}, dct2tbl(d))
+ d.dv_scope = lib.VAR_SCOPE
+ tv_dict_extend(d, d4, 'force',
+ 'E461: Illegal variable name: TEST:THIS')
+ eq({}, dct2tbl(d))
+ tv_dict_extend(d, d2, 'force')
+ eq({tr=f_lua}, dct2tbl(d))
+ tv_dict_extend(d, d3, 'force')
+ eq({tr=p_lua}, dct2tbl(d))
+ tv_dict_extend(d, d5, 'force')
+ eq({tr=p_lua, Test=f_lua}, dct2tbl(d))
+ tv_dict_extend(d, d6, 'force')
+ eq({tr=p_lua, Test=p_lua}, dct2tbl(d))
+ end)
+ itp('cares about locks and read-only items', function()
+ local d_lua = {tv_locked=1, tv_fixed=2, di_ro=3, di_ro_sbx=4}
+ local d = dict(d_lua)
+ local dis = dict_items(d)
+ dis.tv_locked.di_tv.v_lock = lib.VAR_LOCKED
+ dis.tv_fixed.di_tv.v_lock = lib.VAR_FIXED
+ dis.di_ro.di_flags = bit.bor(dis.di_ro.di_flags, lib.DI_FLAGS_RO)
+ dis.di_ro_sbx.di_flags = bit.bor(dis.di_ro_sbx.di_flags, lib.DI_FLAGS_RO_SBX)
+ lib.sandbox = true
+ local d1 = dict({tv_locked=41})
+ local d2 = dict({tv_fixed=42})
+ local d3 = dict({di_ro=43})
+ local d4 = dict({di_ro_sbx=44})
+ tv_dict_extend(d, d1, 'force', 'E741: Value is locked: extend() argument')
+ tv_dict_extend(d, d2, 'force', 'E742: Cannot change value of extend() argument')
+ tv_dict_extend(d, d3, 'force', 'E46: Cannot change read-only variable "extend() argument"')
+ tv_dict_extend(d, d4, 'force', 'E794: Cannot set variable in the sandbox: "extend() argument"')
+ eq(d_lua, dct2tbl(d))
+ lib.sandbox = false
+ tv_dict_extend(d, d4, 'force')
+ d_lua.di_ro_sbx = 44
+ eq(d_lua, dct2tbl(d))
+ end)
+ end)
end)
end)