forked from aniani/vim
patch 8.2.0619: null dict is not handled like an empty dict
Problem: Null dict is not handled like an empty dict. Solution: Fix the code and add tests. (Yegappan Lakshmanan, closes #5968)
This commit is contained in:
parent
db950e4c03
commit
ea04a6e8ba
@ -977,14 +977,15 @@ dict_equal(
|
|||||||
dictitem_T *item2;
|
dictitem_T *item2;
|
||||||
int todo;
|
int todo;
|
||||||
|
|
||||||
if (d1 == NULL && d2 == NULL)
|
|
||||||
return TRUE;
|
|
||||||
if (d1 == NULL || d2 == NULL)
|
|
||||||
return FALSE;
|
|
||||||
if (d1 == d2)
|
if (d1 == d2)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if (dict_len(d1) != dict_len(d2))
|
if (dict_len(d1) != dict_len(d2))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
if (dict_len(d1) == 0)
|
||||||
|
// empty and NULL dicts are considered equal
|
||||||
|
return TRUE;
|
||||||
|
if (d1 == NULL || d2 == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
todo = (int)d1->dv_hashtab.ht_used;
|
todo = (int)d1->dv_hashtab.ht_used;
|
||||||
for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
|
for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
|
||||||
|
@ -871,7 +871,10 @@ get_lval(
|
|||||||
if (len != -1)
|
if (len != -1)
|
||||||
key[len] = prevval;
|
key[len] = prevval;
|
||||||
if (wrong)
|
if (wrong)
|
||||||
|
{
|
||||||
|
clear_tv(&var1);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lp->ll_di == NULL)
|
if (lp->ll_di == NULL)
|
||||||
@ -4553,8 +4556,9 @@ echo_string_core(
|
|||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
if (tv->vval.v_dict == NULL)
|
if (tv->vval.v_dict == NULL)
|
||||||
{
|
{
|
||||||
|
// NULL dict is equivalent to empty dict.
|
||||||
*tofree = NULL;
|
*tofree = NULL;
|
||||||
r = NULL;
|
r = (char_u *)"{}";
|
||||||
}
|
}
|
||||||
else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
|
else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
|
||||||
&& tv->vval.v_dict->dv_hashtab.ht_used != 0)
|
&& tv->vval.v_dict->dv_hashtab.ht_used != 0)
|
||||||
@ -4565,6 +4569,7 @@ echo_string_core(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int old_copyID = tv->vval.v_dict->dv_copyID;
|
int old_copyID = tv->vval.v_dict->dv_copyID;
|
||||||
|
|
||||||
tv->vval.v_dict->dv_copyID = copyID;
|
tv->vval.v_dict->dv_copyID = copyID;
|
||||||
*tofree = dict2string(tv, copyID, restore_copyID);
|
*tofree = dict2string(tv, copyID, restore_copyID);
|
||||||
if (restore_copyID)
|
if (restore_copyID)
|
||||||
|
@ -207,6 +207,7 @@ func Test_blob_add()
|
|||||||
call assert_equal(0z001122, b)
|
call assert_equal(0z001122, b)
|
||||||
call add(b, '51')
|
call add(b, '51')
|
||||||
call assert_equal(0z00112233, b)
|
call assert_equal(0z00112233, b)
|
||||||
|
call assert_equal(1, add(test_null_blob(), 0x22))
|
||||||
|
|
||||||
call assert_fails('call add(b, [9])', 'E745:')
|
call assert_fails('call add(b, [9])', 'E745:')
|
||||||
call assert_fails('call add("", 0x01)', 'E897:')
|
call assert_fails('call add("", 0x01)', 'E897:')
|
||||||
|
@ -96,13 +96,6 @@ func Test_loop_over_null_list()
|
|||||||
endfor
|
endfor
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_compare_null_dict()
|
|
||||||
call assert_fails('let x = test_null_dict()[10]')
|
|
||||||
call assert_equal({}, {})
|
|
||||||
call assert_equal(test_null_dict(), test_null_dict())
|
|
||||||
call assert_notequal({}, test_null_dict())
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func Test_set_reg_null_list()
|
func Test_set_reg_null_list()
|
||||||
call setreg('x', test_null_list())
|
call setreg('x', test_null_list())
|
||||||
endfunc
|
endfunc
|
||||||
|
@ -96,6 +96,7 @@ func Test_map_filter_fails()
|
|||||||
call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:')
|
call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:')
|
||||||
call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:')
|
call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:')
|
||||||
call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:')
|
call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:')
|
||||||
|
call assert_fails("let l = filter([1, 2], {})", 'E731:')
|
||||||
call assert_equal(0, map(test_null_list(), '"> " .. v:val'))
|
call assert_equal(0, map(test_null_list(), '"> " .. v:val'))
|
||||||
call assert_equal(0, map(test_null_dict(), '"> " .. v:val'))
|
call assert_equal(0, map(test_null_dict(), '"> " .. v:val'))
|
||||||
endfunc
|
endfunc
|
||||||
|
@ -274,6 +274,7 @@ func Test_let_errors()
|
|||||||
call assert_fails('let &buftype[1] = "nofile"', 'E18:')
|
call assert_fails('let &buftype[1] = "nofile"', 'E18:')
|
||||||
let s = "var"
|
let s = "var"
|
||||||
let var = 1
|
let var = 1
|
||||||
|
call assert_fails('let var += [1,2]', 'E734:')
|
||||||
call assert_fails('let {s}.1 = 2', 'E18:')
|
call assert_fails('let {s}.1 = 2', 'E18:')
|
||||||
call assert_fails('let a[1] = 5', 'E121:')
|
call assert_fails('let a[1] = 5', 'E121:')
|
||||||
let l = [[1,2]]
|
let l = [[1,2]]
|
||||||
@ -286,6 +287,8 @@ func Test_let_errors()
|
|||||||
call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:')
|
call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:')
|
||||||
call assert_fails('let l[-2:-3] = [3, 4]', 'E684:')
|
call assert_fails('let l[-2:-3] = [3, 4]', 'E684:')
|
||||||
call assert_fails('let l[0:4] = [5, 6]', 'E711:')
|
call assert_fails('let l[0:4] = [5, 6]', 'E711:')
|
||||||
|
call assert_fails('let g:["a;b"] = 10', 'E461:')
|
||||||
|
call assert_fails('let g:.min = function("max")', 'E704:')
|
||||||
|
|
||||||
" This test works only when the language is English
|
" This test works only when the language is English
|
||||||
if v:lang == "C" || v:lang =~ '^[Ee]n'
|
if v:lang == "C" || v:lang =~ '^[Ee]n'
|
||||||
|
@ -32,7 +32,11 @@ func Test_list_slice()
|
|||||||
call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
|
call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
|
||||||
call assert_equal([], l[8:-1])
|
call assert_equal([], l[8:-1])
|
||||||
call assert_equal([], l[0:-10])
|
call assert_equal([], l[0:-10])
|
||||||
call assert_equal([], test_null_list()[:2])
|
" perform an operation on a list slice
|
||||||
|
let l = [1, 2, 3]
|
||||||
|
let l[:1] += [1, 2]
|
||||||
|
let l[2:] -= [1]
|
||||||
|
call assert_equal([2, 4, 2], l)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" List identity
|
" List identity
|
||||||
@ -147,6 +151,20 @@ func Test_list_func_remove()
|
|||||||
call assert_fails("call remove(l, l)", 'E745:')
|
call assert_fails("call remove(l, l)", 'E745:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" List add() function
|
||||||
|
func Test_list_add()
|
||||||
|
let l = []
|
||||||
|
call add(l, 1)
|
||||||
|
call add(l, [2, 3])
|
||||||
|
call add(l, [])
|
||||||
|
call add(l, test_null_list())
|
||||||
|
call add(l, {'k' : 3})
|
||||||
|
call add(l, {})
|
||||||
|
call add(l, test_null_dict())
|
||||||
|
call assert_equal([1, [2, 3], [], [], {'k' : 3}, {}, {}], l)
|
||||||
|
call assert_equal(1, add(test_null_list(), 4))
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Tests for Dictionary type
|
" Tests for Dictionary type
|
||||||
|
|
||||||
func Test_dict()
|
func Test_dict()
|
||||||
@ -529,6 +547,15 @@ func Test_dict_lock_extend()
|
|||||||
call assert_equal({'a': 99, 'b': 100}, d)
|
call assert_equal({'a': 99, 'b': 100}, d)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Cannot use += with a locked dick
|
||||||
|
func Test_dict_lock_operator()
|
||||||
|
unlet! d
|
||||||
|
let d = {}
|
||||||
|
lockvar d
|
||||||
|
call assert_fails("let d += {'k' : 10}", 'E741:')
|
||||||
|
unlockvar d
|
||||||
|
endfunc
|
||||||
|
|
||||||
" No remove() of write-protected scope-level variable
|
" No remove() of write-protected scope-level variable
|
||||||
func Tfunc1(this_is_a_long_parameter_name)
|
func Tfunc1(this_is_a_long_parameter_name)
|
||||||
call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
|
call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
|
||||||
@ -651,8 +678,6 @@ func Test_reverse_sort_uniq()
|
|||||||
call assert_fails("call sort([1, 2], function('min'), 1)", "E715:")
|
call assert_fails("call sort([1, 2], function('min'), 1)", "E715:")
|
||||||
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
|
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
|
||||||
call assert_fails("call sort([1, 2], function('min'))", "E702:")
|
call assert_fails("call sort([1, 2], function('min'))", "E702:")
|
||||||
call assert_equal(0, sort(test_null_list()))
|
|
||||||
call assert_equal(0, uniq(test_null_list()))
|
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" splitting a string to a List using split()
|
" splitting a string to a List using split()
|
||||||
@ -896,23 +921,44 @@ func Test_listdict_index()
|
|||||||
call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:')
|
call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:')
|
||||||
call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:')
|
call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:')
|
||||||
call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:')
|
call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:')
|
||||||
|
let l = [1, 2, 3]
|
||||||
|
call assert_fails("let l[i] = 3", 'E121:')
|
||||||
|
call assert_fails("let l[1.1] = 4", 'E806:')
|
||||||
|
call assert_fails("let l[:i] = [4, 5]", 'E121:')
|
||||||
|
call assert_fails("let l[:3.2] = [4, 5]", 'E806:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for a null list
|
" Test for a null list
|
||||||
func Test_null_list()
|
func Test_null_list()
|
||||||
call assert_equal(0, join(test_null_list()))
|
let l = test_null_list()
|
||||||
|
call assert_equal(0, join(l))
|
||||||
|
call assert_equal(0, len(l))
|
||||||
|
call assert_equal(1, empty(l))
|
||||||
call assert_fails('let s = join([1, 2], [])', 'E730:')
|
call assert_fails('let s = join([1, 2], [])', 'E730:')
|
||||||
call assert_equal([], split(test_null_string()))
|
call assert_equal([], split(test_null_string()))
|
||||||
|
call assert_equal([], l[:2])
|
||||||
|
call assert_true([] == l)
|
||||||
|
call assert_equal('[]', string(l))
|
||||||
|
call assert_equal(0, sort(l))
|
||||||
|
call assert_equal(0, uniq(l))
|
||||||
|
call assert_fails("let k = [] + l", 'E15:')
|
||||||
|
call assert_fails("let k = l + []", 'E15:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for a null dict
|
" Test for a null dict
|
||||||
func Test_null_dict()
|
func Test_null_dict()
|
||||||
call assert_equal(0, items(test_null_dict()))
|
call assert_equal(test_null_dict(), test_null_dict())
|
||||||
call assert_equal(0, keys(test_null_dict()))
|
let d = test_null_dict()
|
||||||
call assert_equal(0, values(test_null_dict()))
|
call assert_equal({}, d)
|
||||||
call assert_false(has_key(test_null_dict(), 'k'))
|
call assert_equal(0, len(d))
|
||||||
call assert_fails("let l = [] + test_null_list()", 'E15:')
|
call assert_equal(1, empty(d))
|
||||||
call assert_fails("let l = test_null_list() + []", 'E15:')
|
call assert_equal(0, items(d))
|
||||||
|
call assert_equal(0, keys(d))
|
||||||
|
call assert_equal(0, values(d))
|
||||||
|
call assert_false(has_key(d, 'k'))
|
||||||
|
call assert_equal('{}', string(d))
|
||||||
|
call assert_fails('let x = test_null_dict()[10]')
|
||||||
|
call assert_equal({}, {})
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -1617,4 +1617,35 @@ func Test_search_in_visual_area()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for searching with 'smartcase' and 'ignorecase'
|
||||||
|
func Test_search_smartcase()
|
||||||
|
new
|
||||||
|
call setline(1, ['', 'Hello'])
|
||||||
|
set noignorecase nosmartcase
|
||||||
|
call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
|
||||||
|
|
||||||
|
set ignorecase nosmartcase
|
||||||
|
exe "normal /\\a\\_.\\(.*\\)O\<CR>"
|
||||||
|
call assert_equal([2, 1], [line('.'), col('.')])
|
||||||
|
|
||||||
|
call cursor(1, 1)
|
||||||
|
set ignorecase smartcase
|
||||||
|
call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
|
||||||
|
|
||||||
|
exe "normal /\\a\\_.\\(.*\\)o\<CR>"
|
||||||
|
call assert_equal([2, 1], [line('.'), col('.')])
|
||||||
|
|
||||||
|
set ignorecase& smartcase&
|
||||||
|
close!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test searching past the end of a file
|
||||||
|
func Test_search_past_eof()
|
||||||
|
new
|
||||||
|
call setline(1, ['Line'])
|
||||||
|
exe "normal /\\n\\zs\<CR>"
|
||||||
|
call assert_equal([1, 4], [line('.'), col('.')])
|
||||||
|
close!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -27,6 +27,7 @@ func Test_unlet_fails()
|
|||||||
call assert_fails("unlet l['k'", 'E111:')
|
call assert_fails("unlet l['k'", 'E111:')
|
||||||
let d = {'k' : 1}
|
let d = {'k' : 1}
|
||||||
call assert_fails("unlet d.k2", 'E716:')
|
call assert_fails("unlet d.k2", 'E716:')
|
||||||
|
call assert_fails("unlet {a};", 'E488:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_unlet_env()
|
func Test_unlet_env()
|
||||||
|
@ -587,17 +587,17 @@ func Test_usercmd_custom()
|
|||||||
return "a\nb\n"
|
return "a\nb\n"
|
||||||
endfunc
|
endfunc
|
||||||
command -nargs=* -complete=customlist,T1 TCmd1
|
command -nargs=* -complete=customlist,T1 TCmd1
|
||||||
call feedkeys(":T1 \<C-A>\<C-B>\"\<CR>", 'xt')
|
call feedkeys(":TCmd1 \<C-A>\<C-B>\"\<CR>", 'xt')
|
||||||
call assert_equal('"T1 ', @:)
|
call assert_equal('"TCmd1 ', @:)
|
||||||
delcommand TCmd1
|
delcommand TCmd1
|
||||||
delfunc T1
|
delfunc T1
|
||||||
|
|
||||||
func T2(a, c, p)
|
func T2(a, c, p)
|
||||||
return ['a', 'b', 'c']
|
return {}
|
||||||
endfunc
|
endfunc
|
||||||
command -nargs=* -complete=customlist,T2 TCmd2
|
command -nargs=* -complete=customlist,T2 TCmd2
|
||||||
call feedkeys(":T2 \<C-A>\<C-B>\"\<CR>", 'xt')
|
call feedkeys(":TCmd2 \<C-A>\<C-B>\"\<CR>", 'xt')
|
||||||
call assert_equal('"T2 ', @:)
|
call assert_equal('"TCmd2 ', @:)
|
||||||
delcommand TCmd2
|
delcommand TCmd2
|
||||||
delfunc T2
|
delfunc T2
|
||||||
endfunc
|
endfunc
|
||||||
|
@ -1671,6 +1671,20 @@ func Test_compound_assignment_operators()
|
|||||||
call assert_fails('let x .= "f"', 'E734')
|
call assert_fails('let x .= "f"', 'E734')
|
||||||
let x = !3.14
|
let x = !3.14
|
||||||
call assert_equal(0.0, x)
|
call assert_equal(0.0, x)
|
||||||
|
|
||||||
|
" integer and float operations
|
||||||
|
let x = 1
|
||||||
|
let x *= 2.1
|
||||||
|
call assert_equal(2.1, x)
|
||||||
|
let x = 1
|
||||||
|
let x /= 0.25
|
||||||
|
call assert_equal(4.0, x)
|
||||||
|
let x = 1
|
||||||
|
call assert_fails('let x %= 0.25', 'E734:')
|
||||||
|
let x = 1
|
||||||
|
call assert_fails('let x .= 0.25', 'E734:')
|
||||||
|
let x = 1.0
|
||||||
|
call assert_fails('let x += [1.1]', 'E734:')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Test for environment variable
|
" Test for environment variable
|
||||||
@ -1871,6 +1885,9 @@ func Test_missing_end()
|
|||||||
|
|
||||||
" Missing 'in' in a :for statement
|
" Missing 'in' in a :for statement
|
||||||
call assert_fails('for i range(1) | endfor', 'E690:')
|
call assert_fails('for i range(1) | endfor', 'E690:')
|
||||||
|
|
||||||
|
" Incorrect number of variables in for
|
||||||
|
call assert_fails('for [i,] in range(3) | endfor', 'E475:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for deep nesting of if/for/while/try statements {{{1
|
" Test for deep nesting of if/for/while/try statements {{{1
|
||||||
|
@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
619,
|
||||||
/**/
|
/**/
|
||||||
618,
|
618,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user