vim-patch:9.1.0797: testing of options can be further improved (#30893)

Problem:  testing of options can be further improved
Solution: split the generated option test into test_options_all.vim,
          add more test cases, save and restore values, fix use-after-free

closes: vim/vim#15894

6eca04e9f1

Co-authored-by: Milly <milly.ca@gmail.com>
This commit is contained in:
zeertzjq
2024-10-22 09:05:14 +08:00
committed by GitHub
parent c8e47f6480
commit f663243e95
7 changed files with 195 additions and 69 deletions

View File

@@ -1417,7 +1417,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'cmdheight'* *'ch'* *'cmdheight'* *'ch'*
'cmdheight' 'ch' number (default 1) 'cmdheight' 'ch' number (default 1)
global or local to tab page |global-local| global or local to tab page
Number of screen lines to use for the command-line. Helps avoiding Number of screen lines to use for the command-line. Helps avoiding
|hit-enter| prompts. |hit-enter| prompts.
The value of this option is stored with the tab page, so that each tab The value of this option is stored with the tab page, so that each tab

View File

@@ -670,7 +670,7 @@ local function scope_to_doc(s)
return m[s[1]] return m[s[1]]
end end
assert(s[1] == 'global') assert(s[1] == 'global')
return 'global or ' .. m[s[2]] .. ' |global-local|' return 'global or ' .. m[s[2]] .. (s[2] ~= 'tab' and ' |global-local|' or '')
end end
-- @param o vim.option_meta -- @param o vim.option_meta

View File

@@ -777,7 +777,11 @@ void getout(int exitval)
} }
} }
if (p_shada && *p_shada != NUL) { if (
#ifdef EXITFREE
!entered_free_all_mem &&
#endif
p_shada && *p_shada != NUL) {
// Write out the registers, history, marks etc, to the ShaDa file // Write out the registers, history, marks etc, to the ShaDa file
shada_write_file(NULL, false); shada_write_file(NULL, false);
} }

View File

@@ -154,7 +154,7 @@ newtests: newtestssilent
newtestssilent: $(NEW_TESTS_RES) newtestssilent: $(NEW_TESTS_RES)
GEN_OPT_DEPS = gen_opt_test.vim ../../../src/nvim/options.lua GEN_OPT_DEPS = gen_opt_test.vim ../../../src/nvim/options.lua ../../../runtime/doc/options.txt
opt_test.vim: $(GEN_OPT_DEPS) opt_test.vim: $(GEN_OPT_DEPS)
$(NVIM_PRG) -e -s -u NONE $(NO_INITS) -S $(GEN_OPT_DEPS) $(NVIM_PRG) -e -s -u NONE $(NO_INITS) -S $(GEN_OPT_DEPS)
@@ -164,7 +164,7 @@ opt_test.vim: $(GEN_OPT_DEPS)
fi fi
# Explicit dependencies. # Explicit dependencies.
test_options.res test_alot.res: opt_test.vim test_options_all.res: opt_test.vim
%.res: %.vim .gdbinit %.res: %.vim .gdbinit
@echo "[OLDTEST] Running" $* @echo "[OLDTEST] Running" $*

View File

@@ -1,4 +1,10 @@
" Script to generate testdir/opt_test.vim from options.lua " Script to generate test/old/testdir/opt_test.vim from src/nvim/options.lua
" and runtime/doc/options.txt
set cpo&vim
" Only do this when build with the +eval feature.
if 1
try try
@@ -6,13 +12,64 @@ set nomore
const K_KENTER = -16715 const K_KENTER = -16715
" Get global-local options.
" "key" is full-name of the option.
" "value" is the local value to switch back to the global value.
b options.txt
call cursor(1, 1)
let global_locals = {}
while search("^'[^']*'.*\\n.*|global-local", 'W')
let fullname = getline('.')->matchstr("^'\\zs[^']*")
let global_locals[fullname] = ''
endwhile
call extend(global_locals, #{
\ scrolloff: -1,
\ sidescrolloff: -1,
\ undolevels: -12345,
\})
" Get local-noglobal options.
" "key" is full-name of the option.
" "value" is no used.
b options.txt
call cursor(1, 1)
let local_noglobals = {}
while search("^'[^']*'.*\\n.*|local-noglobal", 'W')
let fullname = getline('.')->matchstr("^'\\zs[^']*")
let local_noglobals[fullname] = v:true
endwhile
" Options to skip `setglobal` tests.
" "key" is full-name of the option.
" "value" is the reason.
let skip_setglobal_reasons = #{
\ iminsert: 'The global value is always overwritten by the local value',
\ imsearch: 'The global value is always overwritten by the local value',
\ breakindentopt: 'TODO: fix missing error handling for setglobal',
\ colorcolumn: 'TODO: fix missing error handling for setglobal',
\ conceallevel: 'TODO: fix missing error handling for setglobal',
\ foldcolumn: 'TODO: fix missing error handling for setglobal',
\ foldmethod: 'TODO: fix `setglobal fdm=` not given an error',
\ iskeyword: 'TODO: fix missing error handling for setglobal',
\ numberwidth: 'TODO: fix missing error handling for setglobal',
\ scrolloff: 'TODO: fix missing error handling for setglobal',
\ shiftwidth: 'TODO: fix missing error handling for setglobal',
\ sidescrolloff: 'TODO: fix missing error handling for setglobal',
\ signcolumn: 'TODO(nvim): fix missing error handling for setglobal',
\ spelloptions: 'TODO(nvim): fix missing error handling for setglobal',
\ tabstop: 'TODO: fix missing error handling for setglobal',
\ termwinkey: 'TODO: fix missing error handling for setglobal',
\ termwinsize: 'TODO: fix missing error handling for setglobal',
\ textwidth: 'TODO: fix missing error handling for setglobal',
\ winhighlight: 'TODO(nvim): fix missing error handling for setglobal',
\}
" The terminal size is restored at the end. " The terminal size is restored at the end.
let script = [ let script = [
\ '" DO NOT EDIT: Generated with gen_opt_test.vim', \ '" DO NOT EDIT: Generated with gen_opt_test.vim',
\ '" Used by test_options.vim.', \ '" Used by test_options_all.vim.',
\ '', \ '',
\ 'let save_columns = &columns', \ 'scriptencoding utf-8',
\ 'let save_lines = &lines',
\ ] \ ]
let options = luaeval('loadfile("../../../src/nvim/options.lua")().options') let options = luaeval('loadfile("../../../src/nvim/options.lua")().options')
@@ -314,6 +371,27 @@ let test_values = {
\ 'otherstring': [['', 'xxx'], []], \ 'otherstring': [['', 'xxx'], []],
\} \}
" Two lists with values: values that pre- and post-processing in test.
" Clear out t_WS: we don't want to resize the actual terminal.
let test_prepost = {
\ 'browsedir': [["call mkdir('Xdir with space', 'D')"], []],
\ 'columns': [[
\ 'set t_WS=',
\ 'let save_columns = &columns'
\ ], [
\ 'let &columns = save_columns',
\ 'set t_WS&'
\ ]],
\ 'lines': [[
\ 'set t_WS=',
\ 'let save_lines = &lines'
\ ], [
\ 'let &lines = save_lines',
\ 'set t_WS&'
\ ]],
\ 'verbosefile': [[], ['call delete("Xfile")']],
\}
const invalid_options = test_values->keys() const invalid_options = test_values->keys()
\->filter({-> v:val !~# '^other' && !exists($"&{v:val}")}) \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")})
if !empty(invalid_options) if !empty(invalid_options)
@@ -321,70 +399,103 @@ if !empty(invalid_options)
endif endif
for option in options for option in options
let name = option.full_name let fullname = option.full_name
let shortname = get(option, 'abbreviation', name) let shortname = get(option, 'abbreviation', fullname)
if get(option, 'immutable', v:false) if get(option, 'immutable', v:false)
continue continue
endif endif
if has_key(test_values, name) let [valid_values, invalid_values] = test_values[
let a = test_values[name] \ has_key(test_values, fullname) ? fullname
elseif option.type == 'number' \ : option.type == 'number' ? 'othernum'
let a = test_values['othernum'] \ : 'otherstring']
else
let a = test_values['otherstring'] if empty(valid_values) && empty(invalid_values)
endif continue
if len(a[0]) > 0 || len(a[1]) > 0
if name == 'browsedir'
call add(script, 'call mkdir("Xdir with space")')
endif endif
call add(script, $"func Test_opt_set_{fullname}()")
call add(script, $"if exists('+{fullname}') && execute('set!') =~# '\\n..{fullname}\\([=\\n]\\|$\\)'")
call add(script, $"let l:saved = [&g:{fullname}, &l:{fullname}]")
call add(script, 'endif')
let [pre_processing, post_processing] = get(test_prepost, fullname, [[], []])
let script += pre_processing
if option.type == 'boolean' if option.type == 'boolean'
call add(script, 'set ' . name) for opt in [fullname, shortname]
call add(script, 'set ' . shortname) for cmd in ['set', 'setlocal', 'setglobal']
call add(script, 'set no' . name) call add(script, $'{cmd} {opt}')
call add(script, 'set no' . shortname) call add(script, $'{cmd} no{opt}')
call add(script, $'{cmd} inv{opt}')
call add(script, $'{cmd} {opt}!')
endfor
endfor
else " P_NUM || P_STRING
" Normal tests
for opt in [fullname, shortname]
for cmd in ['set', 'setlocal', 'setglobal']
for val in valid_values
if local_noglobals->has_key(fullname) && cmd ==# 'setglobal'
" Skip `:setglobal {option}={val}` for local-noglobal option.
" It has no effect.
let pre = '" Skip local-noglobal: '
else else
for val in a[0] let pre = ''
call add(script, 'set ' . name . '=' . val) endif
call add(script, 'set ' . shortname . '=' . val) call add(script, $'{pre}{cmd} {opt}={val}')
endfor
endfor
" Testing to clear the local value and switch back to the global value.
if global_locals->has_key(fullname)
let swichback_val = global_locals[fullname]
call add(script, $'setlocal {opt}={swichback_val}')
endif
endfor endfor
" setting an option can only fail when it's implemented. " Failure tests
call add(script, "if exists('+" . name . "')") " Setting an option can only fail when it's implemented.
for val in a[1] call add(script, $"if exists('+{fullname}')")
call add(script, "silent! call assert_fails('set " . name . "=" . val . "')") for opt in [fullname, shortname]
call add(script, "silent! call assert_fails('set " . shortname . "=" . val . "')") for cmd in ['set', 'setlocal', 'setglobal']
for val in invalid_values
if val is# global_locals->get(fullname, {}) && cmd ==# 'setlocal'
" Skip setlocal switchback-value to global-local option. It will
" not result in failure.
let pre = '" Skip global-local: '
elseif local_noglobals->has_key(fullname) && cmd ==# 'setglobal'
" Skip setglobal to local-noglobal option. It will not result in
" failure.
let pre = '" Skip local-noglobal: '
elseif skip_setglobal_reasons->has_key(fullname) && cmd ==# 'setglobal'
" Skip setglobal to reasoned option. It will not result in failure.
let reason = skip_setglobal_reasons[fullname]
let pre = $'" Skip {reason}: '
else
let pre = ''
endif
let cmdline = $'{cmd} {opt}={val}'
call add(script, $"{pre}silent! call assert_fails({string(cmdline)})")
endfor
endfor
endfor endfor
call add(script, "endif") call add(script, "endif")
endif endif
" cannot change 'termencoding' in GTK " Cannot change 'termencoding' in GTK
if name != 'termencoding' || !has('gui_gtk') if fullname != 'termencoding' || !has('gui_gtk')
call add(script, 'set ' . name . '&') call add(script, $'set {fullname}&')
call add(script, 'set ' . shortname . '&') call add(script, $'set {shortname}&')
endif call add(script, $"if exists('l:saved')")
if name == 'browsedir' call add(script, $"let [&g:{fullname}, &l:{fullname}] = l:saved")
call add(script, 'call delete("Xdir with space", "d")') call add(script, 'endif')
elseif name == 'verbosefile'
call add(script, 'call delete("Xfile")')
endif endif
if name == 'more' let script += post_processing
call add(script, 'set nomore') call add(script, 'endfunc')
elseif name == 'laststatus'
call add(script, 'set laststatus=1')
elseif name == 'lines'
call add(script, 'let &lines = save_lines')
endif
endif
endfor endfor
call add(script, 'let &columns = save_columns')
call add(script, 'let &lines = save_lines')
call add(script, 'source unix.vim')
call writefile(script, 'opt_test.vim') call writefile(script, 'opt_test.vim')
" Write error messages if error occurs. " Write error messages if error occurs.
@@ -397,4 +508,8 @@ catch
write write
endtry endtry
endif
qa! qa!
" vim:sw=2:ts=8:noet:nolist:nosta:

View File

@@ -1,8 +1,11 @@
" Test for options " Test for options
source shared.vim
source check.vim source check.vim
source view_util.vim source view_util.vim
scriptencoding utf-8
func Test_whichwrap() func Test_whichwrap()
set whichwrap=b,s set whichwrap=b,s
call assert_equal('b,s', &whichwrap) call assert_equal('b,s', &whichwrap)
@@ -1024,15 +1027,6 @@ func Test_set_all_one_column()
call assert_equal(sort(copy(options)), options) call assert_equal(sort(copy(options)), options)
endfunc endfunc
func Test_set_values()
" opt_test.vim is generated from ../optiondefs.h using gen_opt_test.vim
if filereadable('opt_test.vim')
source opt_test.vim
else
throw 'Skipped: opt_test.vim does not exist'
endif
endfunc
func Test_renderoptions() func Test_renderoptions()
throw 'skipped: Nvim does not support renderoptions' throw 'skipped: Nvim does not support renderoptions'
" Only do this for Windows Vista and later, fails on Windows XP and earlier. " Only do this for Windows Vista and later, fails on Windows XP and earlier.

View File

@@ -0,0 +1,13 @@
" Test for options
" opt_test.vim is generated from src/optiondefs.h and runtime/doc/options.txt
" using gen_opt_test.vim
if filereadable('opt_test.vim')
source opt_test.vim
else
func Test_set_values()
throw 'Skipped: opt_test.vim does not exist'
endfunc
endif
" vim: shiftwidth=2 sts=2 expandtab