changeset 19852:12518b40c161 v8.2.0482

patch 8.2.0482: channel and sandbox code not sufficiently tested Commit: https://github.com/vim/vim/commit/ca68ae13114619df3e4c195b41ad0575516f5ff6 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Mar 30 19:32:53 2020 +0200 patch 8.2.0482: channel and sandbox code not sufficiently tested Problem: Channel and sandbox code not sufficiently tested. Solution: Add more tests. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/5855)
author Bram Moolenaar <Bram@vim.org>
date Mon, 30 Mar 2020 19:45:05 +0200
parents e259e7903c55
children f7e6112dda26
files src/option.h src/testdir/test_channel.vim src/testdir/test_clientserver.vim src/testdir/test_cmdline.vim src/testdir/test_edit.vim src/testdir/test_excmd.vim src/testdir/test_normal.vim src/testdir/test_prompt_buffer.vim src/testdir/test_restricted.vim src/testdir/test_smartindent.vim src/testdir/test_substitute.vim src/testdir/test_terminal.vim src/testdir/test_textformat.vim src/testdir/test_visual.vim src/version.c
diffstat 15 files changed, 488 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/src/option.h
+++ b/src/option.h
@@ -403,7 +403,7 @@ EXTERN char_u	*p_bex;		// 'backupext'
 EXTERN char_u	*p_bo;		// 'belloff'
 EXTERN unsigned	bo_flags;
 
-// values for the 'beepon' option
+// values for the 'belloff' option
 #define BO_ALL		0x0001
 #define BO_BS		0x0002
 #define BO_CRSR		0x0004
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -251,6 +251,7 @@ func Ch_two_channels(port)
   call assert_equal('got it', ch_evalexpr(newhandle, 'hello!'))
 
   call ch_close(newhandle)
+  call assert_fails("call ch_close(newhandle)", 'E906:')
 endfunc
 
 func Test_two_channels()
@@ -497,6 +498,11 @@ func Test_raw_pipe()
     call ch_sendraw(job, "double this\n", {'callback': 'Ch_handler'})
     call WaitForAssert({-> assert_equal("this\nAND this\n", substitute(g:Ch_reply, "\r", "", 'g'))})
 
+    call assert_fails("let i = ch_evalraw(job, '2 + 2', {'callback' : 'abc'})", 'E917:')
+    call assert_fails("let i = ch_evalexpr(job, '2 + 2')", 'E912:')
+    call assert_fails("let i = ch_evalraw(job, '2 + 2', {'drop' : ''})", 'E475:')
+    call assert_fails("let i = ch_evalraw(test_null_job(), '2 + 2')", 'E906:')
+
     let reply = job->ch_evalraw("quit\n", {'timeout': 100})
     call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
   finally
@@ -519,6 +525,10 @@ func Test_raw_pipe()
   endfor
   call assert_equal(1, found)
 
+  call assert_fails("call job_stop('abc')", 'E475:')
+  call assert_fails("call job_stop(job, [])", 'E474:')
+  call assert_fails("call job_stop(test_null_job())", 'E916:')
+
   " Try to use the job and channel where a number is expected. This is not
   " related to testing the raw pipe. This test is here just to reuse the
   " already created job/channel.
@@ -620,6 +630,7 @@ func Test_nl_read_file()
     call Stop_g_job()
     call delete('Xinput')
   endtry
+  call assert_fails("echo ch_read(test_null_channel(), {'callback' : 'abc'})", 'E475:')
 endfunc
 
 func Test_nl_write_out_file()
@@ -1362,9 +1373,23 @@ endfunc
 """"""""""
 
 func Test_open_fail()
-  silent! let ch = ch_open("noserver")
+  call assert_fails("let ch = ch_open('noserver')", 'E475:')
   echo ch
   let d = ch
+  call assert_fails("let ch = ch_open('noserver', 10)", 'E474:')
+  call assert_fails("let ch = ch_open('localhost:-1')", 'E475:')
+  call assert_fails("let ch = ch_open('localhost:8765', {'timeout' : -1})",
+        \ 'E474:')
+  call assert_fails("let ch = ch_open('localhost:8765', {'axby' : 1})",
+        \ 'E475:')
+  call assert_fails("let ch = ch_open('localhost:8765', {'mode' : 'abc'})",
+        \ 'E475:')
+  call assert_fails("let ch = ch_open('localhost:8765', {'part' : 'out'})",
+        \ 'E475:')
+endfunc
+
+func Test_ch_info_fail()
+  call assert_fails("let x = ch_info(10)", 'E475:')
 endfunc
 
 """"""""""
@@ -1403,6 +1428,10 @@ function Ch_test_call(port)
   let g:Ch_call_ret = []
   call assert_equal('ok', ch_evalexpr(handle, 'call-func'))
   call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)})
+
+  call assert_fails("let i = ch_evalexpr(handle, '2 + 2', {'callback' : 'abc'})", 'E917:')
+  call assert_fails("let i = ch_evalexpr(handle, '2 + 2', {'drop' : ''})", 'E475:')
+  call assert_fails("let i = ch_evalexpr(test_null_job(), '2 + 2')", 'E906:')
 endfunc
 
 func Test_call()
@@ -1520,9 +1549,68 @@ func Test_close_partial()
   call s:run_server('Ch_test_close_partial')
 endfunc
 
-func Test_job_start_invalid()
+func Test_job_start_fails()
+  " this was leaking memory
+  call assert_fails("call job_start([''])", "E474:")
   call assert_fails('call job_start($x)', 'E474:')
   call assert_fails('call job_start("")', 'E474:')
+  call assert_fails('call job_start("ls", {"out_io" : "abc"})', 'E475:')
+  call assert_fails('call job_start("ls", {"err_io" : "abc"})', 'E475:')
+  call assert_fails('call job_start("ls", [])', 'E715:')
+  call assert_fails("call job_start('ls', {'in_top' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'in_bot' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'channel' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'callback' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'out_cb' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'err_cb' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'close_cb' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'exit_cb' : -1})", 'E475:')
+  call assert_fails("call job_start('ls', {'term_name' : []})", 'E475:')
+  call assert_fails("call job_start('ls', {'term_finish' : 'run'})", 'E475:')
+  call assert_fails("call job_start('ls', {'term_api' : []})", 'E475:')
+  call assert_fails("call job_start('ls', {'stoponexit' : []})", 'E475:')
+  call assert_fails("call job_start('ls', {'in_io' : 'file'})", 'E920:')
+  call assert_fails("call job_start('ls', {'out_io' : 'file'})", 'E920:')
+  call assert_fails("call job_start('ls', {'err_io' : 'file'})", 'E920:')
+  call assert_fails("call job_start('ls', {'in_mode' : 'abc'})", 'E475:')
+  call assert_fails("call job_start('ls', {'out_mode' : 'abc'})", 'E475:')
+  call assert_fails("call job_start('ls', {'err_mode' : 'abc'})", 'E475:')
+  call assert_fails("call job_start('ls',
+        \ {'in_io' : 'buffer', 'in_buf' : 99999})", 'E86:')
+  call assert_fails("call job_start('ls',
+        \ {'out_io' : 'buffer', 'out_buf' : 99999})", 'E86:')
+  call assert_fails("call job_start('ls',
+        \ {'err_io' : 'buffer', 'err_buf' : 99999})", 'E86:')
+
+  call assert_fails("call job_start('ls',
+        \ {'in_io' : 'buffer', 'in_buf' : -1})", 'E475:')
+  call assert_fails("call job_start('ls',
+        \ {'out_io' : 'buffer', 'out_buf' : -1})", 'E475:')
+  call assert_fails("call job_start('ls',
+        \ {'err_io' : 'buffer', 'err_buf' : -1})", 'E475:')
+
+  set nomodifiable
+  call assert_fails("call job_start('cmd /c dir',
+        \ {'out_io' : 'buffer', 'out_buf' :" .. bufnr() .. "})", 'E21:')
+  call assert_fails("call job_start('cmd /c dir',
+        \ {'err_io' : 'buffer', 'err_buf' :" .. bufnr() .. "})", 'E21:')
+  set modifiable
+
+  call assert_fails("call job_start('ls', {'in_io' : 'buffer'})", 'E915:')
+
+  edit! XXX
+  let bnum = bufnr()
+  enew
+  call assert_fails("call job_start('ls',
+        \ {'in_io' : 'buffer', 'in_buf' : bnum})", 'E918:')
+
+  " Empty job tests
+  " This was crashing on MS-Windows.
+  call assert_fails('let job = job_start([""])', 'E474:')
+  call assert_fails('let job = job_start(["   "])', 'E474:')
+  call assert_fails('let job = job_start("")', 'E474:')
+  call assert_fails('let job = job_start("   ")', 'E474:')
+  %bw!
 endfunc
 
 func Test_job_stop_immediately()
@@ -1986,14 +2074,6 @@ func Test_zz_nl_err_to_out_pipe()
   endtry
 endfunc
 
-func Test_empty_job()
-  " This was crashing on MS-Windows.
-  call assert_fails('let job = job_start([""])', 'E474:')
-  call assert_fails('let job = job_start(["   "])', 'E474:')
-  call assert_fails('let job = job_start("")', 'E474:')
-  call assert_fails('let job = job_start("   ")', 'E474:')
-endfunc
-
 " Do this last, it stops any channel log.
 func Test_zz_ch_log()
   call ch_logfile('Xlog', 'w')
@@ -2003,14 +2083,12 @@ func Test_zz_ch_log()
   let text = readfile('Xlog')
   call assert_match("hello there", text[1])
   call assert_match("%s%s", text[2])
+  call mkdir("Xdir1")
+  call assert_fails("call ch_logfile('Xdir1')", 'E484:')
+  cal delete("Xdir1", 'd')
   call delete('Xlog')
 endfunc
 
-func Test_job_start_fails()
-  " this was leaking memory
-  call assert_fails("call job_start([''])", "E474:")
-endfunc
-
 func Test_issue_5150()
   if has('win32')
     let cmd = 'cmd /c pause'
@@ -2048,4 +2126,82 @@ func Test_job_trailing_space_unix()
   call assert_equal(0, job_info(job).exitval)
 endfunc
 
+func Test_ch_getbufnr()
+  let ch = test_null_channel()
+  call assert_equal(-1, ch_getbufnr(ch, 'in'))
+  call assert_equal(-1, ch_getbufnr(ch, 'out'))
+  call assert_equal(-1, ch_getbufnr(ch, 'err'))
+  call assert_equal(-1, ch_getbufnr(ch, ''))
+endfunc
+
+" Test for unsupported options passed to ch_status()
+func Test_invalid_job_chan_options()
+  let ch = test_null_channel()
+  let invalid_opts = [
+        \ {'in_io' : 'null'},
+        \ {'out_io' : 'null'},
+        \ {'err_io' : 'null'},
+        \ {'mode' : 'json'},
+        \ {'out_mode' : 'json'},
+        \ {'err_mode' : 'json'},
+        \ {'noblock' : 1},
+        \ {'in_name' : '/a/b'},
+        \ {'pty' : 1},
+        \ {'in_buf' : 1},
+        \ {'out_buf' : 1},
+        \ {'err_buf' : 1},
+        \ {'out_modifiable' : 1},
+        \ {'err_modifiable' : 1},
+        \ {'out_msg' : 1},
+        \ {'err_msg' : 1},
+        \ {'in_top' : 1},
+        \ {'in_bot' : 1},
+        \ {'channel' : ch},
+        \ {'callback' : ''},
+        \ {'out_cb' : ''},
+        \ {'err_cb' : ''},
+        \ {'close_cb' : ''},
+        \ {'exit_cb' : ''},
+        \ {'term_opencmd' : ''},
+        \ {'eof_chars' : ''},
+        \ {'term_rows' : 10},
+        \ {'term_cols' : 10},
+        \ {'vertical' : 0},
+        \ {'curwin' : 1},
+        \ {'bufnr' : 1},
+        \ {'hidden' : 0},
+        \ {'norestore' : 0},
+        \ {'term_kill' : 'kill'},
+        \ {'tty_type' : ''},
+        \ {'term_highlight' : ''},
+        \ {'env' : {}},
+        \ {'cwd' : ''},
+        \ {'timeout' : 0},
+        \ {'out_timeout' : 0},
+        \ {'err_timeout' : 0},
+        \ {'id' : 0},
+        \ {'stoponexit' : ''},
+        \ {'block_write' : 1}
+        \ ]
+  if has('gui')
+    call add(invalid_opts, {'ansi_colors' : []})
+  endif
+
+  for opt in invalid_opts
+    call assert_fails("let x = ch_status(ch, opt)", 'E475:')
+  endfor
+endfunc
+
+" Test for passing the command and the arguments as List on MS-Windows
+func Test_job_with_list_args()
+  CheckMSWindows
+
+  enew!
+  let bnum = bufnr()
+  let job = job_start(['cmd', '/c', 'echo', 'Hello', 'World'], {'out_io' : 'buffer', 'out_buf' : bnum})
+  call WaitForAssert({-> assert_equal("dead", job_status(job))})
+  call assert_equal('Hello World', getline(1))
+  %bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_clientserver.vim
+++ b/src/testdir/test_clientserver.vim
@@ -39,6 +39,8 @@ func Test_client_server()
   call remote_send(name, ":let testvar = 'yes'\<CR>")
   call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"')
   call assert_equal('yes', remote_expr(name, "testvar", "", 2))
+  call assert_fails("let x=remote_expr(name, '2+x')", 'E449:')
+  call assert_fails("let x=remote_expr('[], '2+2')", 'E116:')
 
   if has('unix') && has('gui') && !has('gui_running')
     " Running in a terminal and the GUI is available: Tell the server to open
@@ -66,6 +68,7 @@ func Test_client_server()
     eval 'MYSELF'->remote_startserver()
     " May get MYSELF1 when running the test again.
     call assert_match('MYSELF', v:servername)
+    call assert_fails("call remote_startserver('MYSELF')", 'E941:')
   endif
   let g:testvar = 'myself'
   call assert_equal('myself', remote_expr(v:servername, 'testvar'))
@@ -100,6 +103,7 @@ func Test_client_server()
   endtry
 
   call assert_fails("let x=remote_peek([])", 'E730:')
+  call assert_fails("let x=remote_read('vim10')", 'E277:')
 endfunc
 
 " Uncomment this line to get a debugging log
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -1459,4 +1459,13 @@ func Test_cmdwin_blocked_commands()
   call assert_fails('call feedkeys("q:\<F1>\<CR>", "xt")', 'E11:')
 endfunc
 
+" Close the Cmd-line window in insert mode using CTRL-C
+func Test_cmdwin_insert_mode_close()
+  %bw!
+  let s = ''
+  exe "normal q:a\<C-C>let s='Hello'\<CR>"
+  call assert_equal('Hello', s)
+  call assert_equal(1, winnr('$'))
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -1542,8 +1542,8 @@ func Test_edit_ctrl_o_invalid_cmd()
   close!
 endfunc
 
-" Test for inserting text at the beginning of a line
-func Test_insert_before_first_nonblank()
+" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
+func Test_edit_cpo_H()
   new
   call setline(1, '    ')
   normal! Ia
@@ -1556,4 +1556,23 @@ func Test_insert_before_first_nonblank()
   close!
 endfunc
 
+" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
+func Test_edit_cpo_L()
+  new
+  call setline(1, 'abcdefghijklmnopqr')
+  exe "normal 0gR\<Tab>"
+  call assert_equal("\<Tab>ijklmnopqr", getline(1))
+  set cpo+=L
+  set list
+  call setline(1, 'abcdefghijklmnopqr')
+  exe "normal 0gR\<Tab>"
+  call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
+  set nolist
+  call setline(1, 'abcdefghijklmnopqr')
+  exe "normal 0gR\<Tab>"
+  call assert_equal("\<Tab>ijklmnopqr", getline(1))
+  set cpo-=L
+  %bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_excmd.vim
+++ b/src/testdir/test_excmd.vim
@@ -409,4 +409,69 @@ func Test_excmd_delete()
   close!
 endfunc
 
+" Test for commands that are blocked in a sandbox
+func Sandbox_tests()
+  call assert_fails("call histadd(':', 'ls')", 'E48:')
+  call assert_fails("call mkdir('Xdir')", 'E48:')
+  call assert_fails("call rename('a', 'b')", 'E48:')
+  call assert_fails("call setbufvar(1, 'myvar', 1)", 'E48:')
+  call assert_fails("call settabvar(1, 'myvar', 1)", 'E48:')
+  call assert_fails("call settabwinvar(1, 1, 'myvar', 1)", 'E48:')
+  call assert_fails("call setwinvar(1, 'myvar', 1)", 'E48:')
+  call assert_fails("call timer_start(100, '')", 'E48:')
+  if has('channel')
+    call assert_fails("call prompt_setcallback(1, '')", 'E48:')
+    call assert_fails("call prompt_setinterrupt(1, '')", 'E48:')
+    call assert_fails("call prompt_setprompt(1, '')", 'E48:')
+  endif
+  call assert_fails("let $TESTVAR=1", 'E48:')
+  call assert_fails("call feedkeys('ivim')", 'E48:')
+  call assert_fails("source! Xfile", 'E48:')
+  call assert_fails("call delete('Xfile')", 'E48:')
+  call assert_fails("call writefile([], 'Xfile')", 'E48:')
+  call assert_fails('!ls', 'E48:')
+  call assert_fails('shell', 'E48:')
+  call assert_fails('stop', 'E48:')
+  call assert_fails('exe "normal \<C-Z>"', 'E48:')
+  set insertmode
+  call assert_fails('call feedkeys("\<C-Z>", "xt")', 'E48:')
+  set insertmode&
+  call assert_fails('suspend', 'E48:')
+  call assert_fails('call system("ls")', 'E48:')
+  call assert_fails('call systemlist("ls")', 'E48:')
+  if has('clientserver')
+    call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:')
+    if !has('win32')
+      " remote_foreground() doesn't thrown an error message on MS-Windows
+      call assert_fails('call remote_foreground("gvim")', 'E48:')
+    endif
+    call assert_fails('let s=remote_peek("gvim")', 'E48:')
+    call assert_fails('let s=remote_read("gvim")', 'E48:')
+    call assert_fails('let s=remote_send("gvim", "abc")', 'E48:')
+    call assert_fails('let s=server2client("gvim", "abc")', 'E48:')
+  endif
+  if has('terminal')
+    call assert_fails('terminal', 'E48:')
+    call assert_fails('call term_start("vim")', 'E48:')
+    call assert_fails('call term_dumpwrite(1, "Xfile")', 'E48:')
+  endif
+  if has('channel')
+    call assert_fails("call ch_logfile('chlog')", 'E48:')
+    call assert_fails("call ch_open('localhost:8765')", 'E48:')
+  endif
+  if has('job')
+    call assert_fails("call job_start('vim')", 'E48:')
+  endif
+  if has('unix') && has('libcall')
+    call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E48:')
+  endif
+  if has('unix')
+    call assert_fails('cd `pwd`', 'E48:')
+  endif
+endfunc
+
+func Test_sandbox()
+  sandbox call Sandbox_tests()
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -2,6 +2,7 @@
 
 source shared.vim
 source check.vim
+source view_util.vim
 
 func Setup_NewWindow()
   10new
@@ -2941,6 +2942,28 @@ func Test_normal_cpo_minus()
   close!
 endfunc
 
+" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
+func Test_normal_cpo_dollar()
+  new
+  let g:Line = ''
+  func SaveFirstLine()
+    let g:Line = Screenline(1)
+    return ''
+  endfunc
+  inoremap <expr> <buffer> <F2> SaveFirstLine()
+  call test_override('redraw_flag', 1)
+  set cpo+=$
+  call setline(1, 'one two three')
+  redraw!
+  exe "normal c2w\<F2>vim"
+  call assert_equal('one tw$ three', g:Line)
+  call assert_equal('vim three', getline(1))
+  set cpo-=$
+  call test_override('ALL', 0)
+  delfunc SaveFirstLine
+  %bw!
+endfunc
+
 " Test for using : to run a multi-line Ex command in operator pending mode
 func Test_normal_yank_with_excmd()
   new
--- a/src/testdir/test_prompt_buffer.vim
+++ b/src/testdir/test_prompt_buffer.vim
@@ -121,6 +121,11 @@ func Test_prompt_garbage_collect()
   call feedkeys("\<CR>\<C-C>", 'xt')
   call assert_true(v:true)
 
+  call assert_fails("call prompt_setcallback(bufnr(), [])", 'E921:')
+  call assert_equal(0, prompt_setcallback({}, ''))
+  call assert_fails("call prompt_setinterrupt(bufnr(), [])", 'E921:')
+  call assert_equal(0, prompt_setinterrupt({}, ''))
+
   delfunc MyPromptCallback
   bwipe!
 endfunc
--- a/src/testdir/test_restricted.vim
+++ b/src/testdir/test_restricted.vim
@@ -78,7 +78,7 @@ func Test_restricted_mode()
       call assert_fails("call job_start('vim')", 'E145:')
     endif
 
-    if has('libcall')
+    if has('unix') && has('libcall')
       call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E145:')
     endif
     call assert_fails("call rename('a', 'b')", 'E145:')
@@ -87,9 +87,13 @@ func Test_restricted_mode()
     call assert_fails('!ls', 'E145:')
     call assert_fails('shell', 'E145:')
     call assert_fails('stop', 'E145:')
+    call assert_fails('exe "normal \<C-Z>"', 'E145:')
+    set insertmode
+    call assert_fails('call feedkeys("\<C-Z>", "xt")', 'E145:')
+    set insertmode&
     call assert_fails('suspend', 'E145:')
-    call assert_fails('call system("vim")', 'E145:')
-    call assert_fails('call systemlist("vim")', 'E145:')
+    call assert_fails('call system("ls")', 'E145:')
+    call assert_fails('call systemlist("ls")', 'E145:')
     if has('unix')
       call assert_fails('cd `pwd`', 'E145:')
     endif
--- a/src/testdir/test_smartindent.vim
+++ b/src/testdir/test_smartindent.vim
@@ -21,9 +21,7 @@ endfunc
 func Test_smartindent_has_no_effect()
   new
   exe "normal! i\<Tab>one\<Esc>"
-  set noautoindent
-  set smartindent
-  set indentexpr=
+  setlocal noautoindent smartindent indentexpr=
   exe "normal! Gotwo\<Esc>"
   call assert_equal("\ttwo", getline("$"))
 
@@ -32,16 +30,13 @@ func Test_smartindent_has_no_effect()
   call assert_equal("three", getline("$"))
 
   delfunction! MyIndent
-  set autoindent&
-  set smartindent&
-  set indentexpr&
   bwipe!
 endfunc
 
 " Test for inserting '{' and '} with smartindent
 func Test_smartindent_braces()
   new
-  set smartindent shiftwidth=4
+  setlocal smartindent shiftwidth=4
   call setline(1, ['    if (a)', "\tif (b)", "\t    return 1"])
   normal 2ggO{
   normal 3ggA {
@@ -57,7 +52,62 @@ func Test_smartindent_braces()
         \ "\t}",
         \ '    }'
         \ ], getline(1, '$'))
-  set si& sw& ai&
+  close!
+endfunc
+
+" Test for adding a new line before and after comments with smartindent
+func Test_si_add_line_around_comment()
+  new
+  setlocal smartindent shiftwidth=4
+  call setline(1, ['    A', '# comment1', '# comment2'])
+  exe "normal GoC\<Esc>2GOB"
+  call assert_equal(['    A', '    B', '# comment1', '# comment2', '    C'],
+        \ getline(1, '$'))
+  close!
+endfunc
+
+" After a C style comment, indent for a following line should line up with the
+" line containing the start of the comment.
+func Test_si_indent_after_c_comment()
+  new
+  setlocal smartindent shiftwidth=4 fo+=ro
+  exe "normal i\<C-t>/*\ncomment\n/\n#define FOOBAR\n75\<Esc>ggOabc"
+  normal 3jOcont
+  call assert_equal(['    abc', '    /*', '     * comment', '     * cont',
+        \ '     */', '#define FOOBAR', '    75'], getline(1, '$'))
+  close!
+endfunc
+
+" Test for indenting a statement after a if condition split across lines
+func Test_si_if_cond_split_across_lines()
+  new
+  setlocal smartindent shiftwidth=4
+  exe "normal i\<C-t>if (cond1 &&\n\<C-t>cond2) {\ni = 10;\n}"
+  call assert_equal(['    if (cond1 &&', "\t    cond2) {", "\ti = 10;",
+        \ '    }'], getline(1, '$'))
+  close!
+endfunc
+
+" Test for inserting lines before and after a one line comment
+func Test_si_one_line_comment()
+  new
+  setlocal smartindent shiftwidth=4
+  exe "normal i\<C-t>abc;\n\<C-t>/* comment */"
+  normal oi = 10;
+  normal kOj = 1;
+  call assert_equal(['    abc;', "\tj = 1;", "\t/* comment */", "\ti = 10;"],
+        \ getline(1, '$'))
+  close!
+endfunc
+
+" Test for smartindent with a comment continued across multiple lines
+func Test_si_comment_line_continuation()
+  new
+  setlocal smartindent shiftwidth=4
+  call setline(1, ['# com1', '# com2 \', '    contd', '# com3', '  xyz'])
+  normal ggOabc
+  call assert_equal(['  abc', '# com1', '# com2 \', '    contd', '# com3',
+        \ '  xyz'], getline(1, '$'))
   close!
 endfunc
 
--- a/src/testdir/test_substitute.vim
+++ b/src/testdir/test_substitute.vim
@@ -840,4 +840,8 @@ func Test_sub_with_no_last_pat()
   call delete('Xresult')
 endfunc
 
+func Test_substitute()
+  call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -1001,6 +1001,28 @@ func Test_terminal_term_start_empty_comm
   call assert_fails(cmd, 'E474')
   let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
   call assert_fails(cmd, 'E474')
+  let cmd = "call term_start('', {'term_name' : []})"
+  call assert_fails(cmd, 'E475')
+  let cmd = "call term_start('', {'term_finish' : 'axby'})"
+  call assert_fails(cmd, 'E475')
+  let cmd = "call term_start('', {'eof_chars' : []})"
+  call assert_fails(cmd, 'E475:')
+  let cmd = "call term_start('', {'term_kill' : []})"
+  call assert_fails(cmd, 'E475:')
+  let cmd = "call term_start('', {'tty_type' : []})"
+  call assert_fails(cmd, 'E475:')
+  let cmd = "call term_start('', {'tty_type' : 'abc'})"
+  call assert_fails(cmd, 'E475:')
+  let cmd = "call term_start('', {'term_highlight' : []})"
+  call assert_fails(cmd, 'E475:')
+  if has('gui')
+    let cmd = "call term_start('', {'ansi_colors' : 'abc'})"
+    call assert_fails(cmd, 'E475:')
+    let cmd = "call term_start('', {'ansi_colors' : [[]]})"
+    call assert_fails(cmd, 'E730:')
+    let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})"
+    call assert_fails(cmd, 'E475:')
+  endif
 endfunc
 
 func Test_terminal_response_to_control_sequence()
@@ -1285,6 +1307,7 @@ func Test_terminal_dumpdiff_options()
   call assert_equal(1, winnr('$'))
   call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
   call assert_equal(1, winnr('$'))
+  call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:')
   bwipe
 
   set laststatus&
@@ -1486,6 +1509,8 @@ func Test_terminal_api_call()
   call assert_equal(['hello', 123], g:called_arg2)
   call StopVimInTerminal(buf)
 
+  call assert_fails("call term_start('ls', {'term_api' : []})", 'E475:')
+
   unlet! g:called_bufnum2
   unlet! g:called_arg2
 
@@ -2552,3 +2577,5 @@ func Test_term_nasty_callback()
   exe g:buf0 .. 'bwipe!'
   set hidden&
 endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_textformat.vim
+++ b/src/testdir/test_textformat.vim
@@ -951,8 +951,88 @@ func Test_whichwrap_multi_byte()
   bwipe!
 endfunc
 
-func Test_substitute()
-  call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+" Test for the 'f' flag in 'comments' (only the first line has the comment
+" string)
+func Test_firstline_comment()
+  new
+  setlocal comments=f:- fo+=ro
+  exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+  call assert_equal(['A', '- B', '  C', '  D'], getline(1, '$'))
+  %d
+  setlocal comments=:-
+  exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+  call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$'))
+  %bw!
+endfunc
+
+" Test for the 'r' flag in 'comments' (right align comment)
+func Test_comment_rightalign()
+  new
+  setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro
+  exe "normal i=\<C-C>o\t  /***\nD\n/"
+  exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG"
+  let expected =<< trim END
+    =
+    A
+    	  /***
+    	    ** B
+    	    ** C
+    	    ** D
+    	    ** E
+    	    **     F
+    	    ******/
+    G
+  END
+  call assert_equal(expected, getline(1, '$'))
+  %bw!
+endfunc
+
+" Test for the 'b' flag in 'comments'
+func Test_comment_blank()
+  new
+  setlocal comments=b:* fo+=ro
+  exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD"
+  let expected =<< trim END
+    A
+    *B
+    * C
+    * D
+    * E
+    * F
+    *G
+    H
+  END
+  call assert_equal(expected, getline(1, '$'))
+  %bw!
+endfunc
+
+" Test for the 'n' flag in comments
+func Test_comment_nested()
+  new
+  setlocal comments=n:> fo+=ro
+  exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH"
+  exe "normal 5GOE\<C-C>6GoG"
+  let expected =<< trim END
+    > A
+    > B
+    > C
+    > D
+    >>>> E
+    >>>> F
+    >>>> G
+    >>>> H
+  END
+  call assert_equal(expected, getline(1, '$'))
+  %bw!
+endfunc
+
+" Test for 'a' and 'w' flags in 'formatoptions'
+func Test_fo_a_w()
+  new
+  setlocal fo+=aw tw=10
+  call feedkeys("iabc abc a abc\<Esc>k0weade", 'xt')
+  call assert_equal(['abc abcde ', 'a abc'], getline(1, '$'))
+  %bw!
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_visual.vim
+++ b/src/testdir/test_visual.vim
@@ -267,6 +267,15 @@ func Test_virtual_replace2()
   call assert_equal(['abcd',
         \ 'efgh',
         \ 'ijkl'], getline(1, '$'))
+
+  " Test for truncating spaces in a newly added line using 'autoindent' if
+  " characters are not added to that line.
+  %d_
+  call setline(1, ['    app', '    bee', '    cat'])
+  setlocal autoindent
+  exe "normal gg$gRt\n\nr"
+  call assert_equal(['    apt', '', '    rat'], getline(1, '$'))
+
   " clean up
   %d_
   set bs&vim
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    482,
+/**/
     481,
 /**/
     480,