unittests: Add tests for tv_dict_extend

This commit is contained in:
ZyX 2017-03-13 14:35:53 +03:00
parent fa852e7cdc
commit 8b9a1fbf7a
3 changed files with 144 additions and 11 deletions

View File

@ -498,6 +498,16 @@ local function dict_watchers(d)
return ret, qs, key_patterns return ret, qs, key_patterns
end 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 { return {
int=int, int=int,
@ -540,5 +550,7 @@ return {
tbl2callback=tbl2callback, tbl2callback=tbl2callback,
callback2tbl=callback2tbl, callback2tbl=callback2tbl,
eval0=eval0,
empty_list = {[type_key]=list_type}, empty_list = {[type_key]=list_type},
} }

View File

@ -1,4 +1,6 @@
local helpers = require('test.unit.helpers')(after_each) local helpers = require('test.unit.helpers')(after_each)
local eval_helpers = require('test.unit.eval.helpers')
local itp = helpers.gen_itp(it) local itp = helpers.gen_itp(it)
local cimport = helpers.cimport local cimport = helpers.cimport
@ -6,19 +8,11 @@ local to_cstr = helpers.to_cstr
local ffi = helpers.ffi local ffi = helpers.ffi
local eq = helpers.eq local eq = helpers.eq
local eval0 = eval_helpers.eval0
local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h', local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h',
'./src/nvim/memory.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() describe('NULL typval_T', function()
itp('is produced by $XXX_UNEXISTENT_VAR_XXX', function() itp('is produced by $XXX_UNEXISTENT_VAR_XXX', function()
-- Required for various tests which need to check whether typval_T with NULL -- Required for various tests which need to check whether typval_T with NULL

View File

@ -1,6 +1,7 @@
local bit = require('bit')
local helpers = require('test.unit.helpers')(after_each) local helpers = require('test.unit.helpers')(after_each)
local global_helpers = require('test.helpers')
local eval_helpers = require('test.unit.eval.helpers') local eval_helpers = require('test.unit.eval.helpers')
local global_helpers = require('test.helpers')
local itp = helpers.gen_itp(it) local itp = helpers.gen_itp(it)
@ -17,6 +18,7 @@ local a = eval_helpers.alloc_logging_helpers
local int = eval_helpers.int local int = eval_helpers.int
local list = eval_helpers.list local list = eval_helpers.list
local dict = eval_helpers.dict local dict = eval_helpers.dict
local eval0 = eval_helpers.eval0
local lst2tbl = eval_helpers.lst2tbl local lst2tbl = eval_helpers.lst2tbl
local dct2tbl = eval_helpers.dct2tbl local dct2tbl = eval_helpers.dct2tbl
local typvalt = eval_helpers.typvalt local typvalt = eval_helpers.typvalt
@ -1905,5 +1907,130 @@ describe('typval.c', function()
eq({}, dct2tbl(d)) eq({}, dct2tbl(d))
end) end)
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)
end) end)