patch 9.1.0797: testing of options can be further improved

Commit: 
https://github.com/vim/vim/commit/6eca04e9f1d446dc509ba51e32da56fa413fe2f0
Author: Milly <milly...@gmail.com>
Date:   Mon Oct 21 22:20:51 2024 +0200

    patch 9.1.0797: testing of options can be further improved
    
    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: #15894
    
    Signed-off-by: Milly <milly...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/main.c b/src/main.c
index e5faaa720..ecc61f4d0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1694,7 +1694,11 @@ getout(int exitval)
     }
 
 #ifdef FEAT_VIMINFO
-    if (*p_viminfo != NUL)
+    if (
+# ifdef EXITFREE
+           entered_free_all_mem == FALSE &&
+# endif
+           *p_viminfo != NUL)
        // Write out the registers, history, marks etc, to the viminfo file
        write_viminfo(NULL, FALSE);
 #endif
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 67ef64100..750c1940a 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -232,6 +232,7 @@ NEW_TESTS = \
        test_normal \
        test_number \
        test_options \
+       test_options_all \
        test_packadd \
        test_partial \
        test_paste \
@@ -492,6 +493,7 @@ NEW_TESTS_RES = \
        test_normal.res \
        test_number.res \
        test_options.res \
+       test_options_all.res \
        test_packadd.res \
        test_partial.res \
        test_paste.res \
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
index 16632b350..2ffe4025e 100644
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -22,7 +22,7 @@ default: nongui
 include Make_all.mak
 
 # Explicit dependencies.
-test_options.res test_alot.res: opt_test.vim
+test_options_all.res: opt_test.vim
 
 TEST_OUTFILES = $(SCRIPTS_TINY_OUT)
 DOSTMP = dostmp
@@ -157,7 +157,7 @@ test_gui_init.res: test_gui_init.vim
        $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S 
runtest.vim $<
        @$(DEL) vimcmd
 
-opt_test.vim: gen_opt_test.vim ../optiondefs.h
+opt_test.vim: gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt
        $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S $^
        @if test -f test.log; then \
                cat test.log; \
diff --git a/src/testdir/Make_mvc.mak b/src/testdir/Make_mvc.mak
index bbfd8f09e..1a54823e5 100644
--- a/src/testdir/Make_mvc.mak
+++ b/src/testdir/Make_mvc.mak
@@ -16,7 +16,7 @@ default: nongui
 !include Make_all.mak
 
 # Explicit dependencies.
-test_options.res test_alot.res: opt_test.vim
+test_options_all.res: opt_test.vim
 
 TEST_OUTFILES = $(SCRIPTS_TINY_OUT)
 DOSTMP = dostmp
@@ -151,7 +151,7 @@ test_gui_init.res: test_gui_init.vim
        $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S 
runtest.vim $*.vim
        @del vimcmd
 
-opt_test.vim: gen_opt_test.vim ../optiondefs.h
+opt_test.vim: gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt
        $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S $**
        @if exist test.log ( type test.log & exit /b 1 )
 
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index 66b8f1b74..3b665e707 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -30,7 +30,7 @@ default: nongui
 include Make_all.mak
 
 # Explicit dependencies.
-test_options.res test_alot.res: opt_test.vim
+test_options_all.res: opt_test.vim
 
 .SUFFIXES: .in .out .res .vim
 
@@ -160,7 +160,7 @@ test_gui_init.res: test_gui_init.vim
        $(RUN_VIMTEST) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S 
runtest.vim $<
        @rm vimcmd
 
-GEN_OPT_DEPS = gen_opt_test.vim ../optiondefs.h
+GEN_OPT_DEPS = gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt
 
 opt_test.vim: $(GEN_OPT_DEPS)
        $(VIMPROG) -e -s -u NONE $(NO_INITS) --nofork --gui-dialog-file 
guidialog -S $(GEN_OPT_DEPS)
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index f308e0ec1..e85560252 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -1,4 +1,5 @@
-" Script to generate testdir/opt_test.vim from optiondefs.h
+" Script to generate src/testdir/opt_test.vim from src/optiondefs.h and
+" runtime/doc/options.txt
 
 set cpo=&vim
 
@@ -11,19 +12,65 @@ set nomore
 
 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',
+      \ 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',
+      \}
+
 " The terminal size is restored at the end.
-" Clear out t_WS, we don't want to resize the actual terminal.
 let script = [
       \ '" DO NOT EDIT: Generated with gen_opt_test.vim',
-      \ '" Used by test_options.vim.',
+      \ '" Used by test_options_all.vim.',
       \ '',
-      \ 'let save_columns = &columns',
-      \ 'let save_lines = &lines',
-      \ 'set t_WS=',
+      \ 'scriptencoding utf-8',
       \ ]
 
-/#define p_term
-let end = line('.')
+b optiondefs.h
+const end = search('#define p_term', 'nw')
 
 " font name that works everywhere (hopefully)
 let fontname = has('win32') ? 'fixedsys' : 'fixed'
@@ -295,6 +342,27 @@ let test_values = {
       \ '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()
       \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")})
 if !empty(invalid_options)
@@ -302,69 +370,104 @@ if !empty(invalid_options)
 endif
 
 1
-/struct vimoption options
+call search('struct vimoption options')
 while 1
-  /{"
-  if line('.') > end
+  if search('{"', 'W') > end
     break
   endif
   let line = getline('.')
-  let name = substitute(line, '.*{"\([^"]*\)".*', ' ', '')
+  let fullname = substitute(line, '.*{"\([^"]*\)".*', ' ', '')
   let shortname = substitute(line, '.*"\([^"]*\)".*', ' ', '')
 
-  if has_key(test_values, name)
-    let a = test_values[name]
-  elseif line =~ 'P_NUM'
-    let a = test_values['othernum']
-  else
-    let a = test_values['otherstring']
+  let [valid_values, invalid_values] = test_values[
+       \ has_key(test_values, fullname) ? fullname
+       \ : line =~ 'P_NUM' ? 'othernum'
+       \ : 'otherstring']
+
+  if empty(valid_values) && empty(invalid_values)
+    continue
   endif
-  if len(a[0]) > 0 || len(a[1]) > 0
-    if name == 'browsedir'
-      call add(script, 'call mkdir("Xdir with space")')
-    endif
 
-    if line =~ 'P_BOOL'
-      call add(script, 'set ' . name)
-      call add(script, 'set ' . shortname)
-      call add(script, 'set no' . name)
-      call add(script, 'set no' . shortname)
-    else
-      for val in a[0]
-       call add(script, 'set ' . name . '=' . val)
-       call add(script, 'set ' . shortname . '=' . val)
-      endfor
+  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
 
-      " setting an option can only fail when it's implemented.
-      call add(script, "if exists('+" . name . "')")
-      for val in a[1]
-       call add(script, "silent! call assert_fails('set " . name . "=" . val . 
"')")
-       call add(script, "silent! call assert_fails('set " . shortname . "=" . 
val . "')")
+  if line =~ 'P_BOOL'
+    for opt in [fullname, shortname]
+      for cmd in ['set', 'setlocal', 'setglobal']
+       call add(script, $'{cmd} {opt}')
+       call add(script, $'{cmd} no{opt}')
+       call add(script, $'{cmd} inv{opt}')
+       call add(script, $'{cmd} {opt}!')
       endfor
-      call add(script, "endif")
-    endif
+    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
+           let pre = ''
+         endif
+         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
 
-    " cannot change 'termencoding' in GTK
-    if name != 'termencoding' || !has('gui_gtk')
-      call add(script, 'set ' . name . '&')
-      call add(script, 'set ' . shortname . '&')
-    endif
-    if name == 'browsedir'
-      call add(script, 'call delete("Xdir with space", "d")')
-    elseif name == 'verbosefile'
-      call add(script, 'call delete("Xfile")')
-    endif
+    " Failure tests
+    " Setting an option can only fail when it's implemented.
+    call add(script, $"if exists('+{fullname}')")
+    for opt in [fullname, shortname]
+      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
+    call add(script, "endif")
+  endif
 
-    if name == 'more'
-      call add(script, 'set nomore')
-    elseif name == 'lines'
-      call add(script, 'let &lines = save_lines')
-    endif
+  " Cannot change 'termencoding' in GTK
+  if fullname != 'termencoding' || !has('gui_gtk')
+    call add(script, $'set {fullname}&')
+    call add(script, $'set {shortname}&')
+    call add(script, $"if exists('l:saved')")
+    call add(script, $"let [&g:{fullname}, &l:{fullname}] = l:saved")
+    call add(script, 'endif')
   endif
-endwhile
 
-call add(script, 'let &columns = save_columns')
-call add(script, 'let &lines = save_lines')
+  let script += post_processing
+  call add(script, 'endfunc')
+endwhile
 
 call writefile(script, 'opt_test.vim')
 
@@ -381,3 +484,5 @@ endtry
 endif
 
 qa!
+
+" vim:sw=2:ts=8:noet:nolist:nosta:
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index eec71efeb..cbc84a471 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -4,6 +4,8 @@ source shared.vim
 source check.vim
 source view_util.vim
 
+scriptencoding utf-8
+
 func Test_whichwrap()
   set whichwrap=b,s
   call assert_equal('b,s', &whichwrap)
@@ -1037,15 +1039,6 @@ func Test_set_all_one_column()
   call assert_equal(sort(copy(options)), options)
 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()
   " Only do this for Windows Vista and later, fails on Windows XP and earlier.
   " Doesn't hurt to do this on a non-Windows system.
diff --git a/src/testdir/test_options_all.vim b/src/testdir/test_options_all.vim
new file mode 100644
index 000000000..a2330ecb9
--- /dev/null
+++ b/src/testdir/test_options_all.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index e979c0456..cd49f58fd 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    797,
 /**/
     796,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1t2z2R-00Fa4D-9t%40256bit.org.

Raspunde prin e-mail lui