diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/ex_cmds.c | 17 | ||||
-rw-r--r-- | src/nvim/testdir/test_buffer.vim | 20 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 21 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_startup.vim | 15 | ||||
-rw-r--r-- | src/nvim/testdir/test_writefile.vim | 219 |
6 files changed, 290 insertions, 3 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 89e6d47950..d3a4b6c282 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1772,6 +1772,17 @@ void ex_write(exarg_T *eap) } } +#ifdef UNIX +static int check_writable(const char *fname) +{ + if (os_nodetype(fname) == NODE_OTHER) { + semsg(_("E503: \"%s\" is not a file or writable device"), fname); + return FAIL; + } + return OK; +} +#endif + /// write current buffer to file 'eap->arg' /// if 'eap->append' is true, append to the file /// @@ -1829,7 +1840,11 @@ int do_write(exarg_T *eap) // Writing to the current file is not allowed in readonly mode // and a file name is required. // "nofile" and "nowrite" buffers cannot be written implicitly either. - if (!other && (bt_dontwrite_msg(curbuf) || check_fname() == FAIL + if (!other && (bt_dontwrite_msg(curbuf) + || check_fname() == FAIL +#ifdef UNIX + || check_writable(curbuf->b_ffname) == FAIL +#endif || check_readonly(&eap->forceit, curbuf))) { goto theend; } diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim index d8d22ff872..3300278802 100644 --- a/src/nvim/testdir/test_buffer.vim +++ b/src/nvim/testdir/test_buffer.vim @@ -434,4 +434,24 @@ func Test_buf_pattern_invalid() bwipe! endfunc +" Test for the 'maxmem' and 'maxmemtot' options +func Test_buffer_maxmem() + " use 1KB per buffer and 2KB for all the buffers + " set maxmem=1 maxmemtot=2 + new + let v:errmsg = '' + " try opening some files + edit test_arglist.vim + call assert_equal('test_arglist.vim', bufname()) + edit test_eval_stuff.vim + call assert_equal('test_eval_stuff.vim', bufname()) + b test_arglist.vim + call assert_equal('test_arglist.vim', bufname()) + b test_eval_stuff.vim + call assert_equal('test_eval_stuff.vim', bufname()) + close + call assert_equal('', v:errmsg) + " set maxmem& maxmemtot& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 7cef3117c2..b0be7ab396 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -1513,6 +1513,7 @@ func Test_cmdline_expand_special() call assert_fails('e <afile>', 'E495:') call assert_fails('e <abuf>', 'E496:') call assert_fails('e <amatch>', 'E497:') + call writefile([], 'Xfile.cpp') call writefile([], 'Xfile.java') new Xfile.cpp @@ -2006,6 +2007,26 @@ func Test_recalling_cmdline() cunmap <Plug>(save-cmdline) endfunc +" Test for the 'suffixes' option +func Test_suffixes_opt() + call writefile([], 'Xfile') + call writefile([], 'Xfile.c') + call writefile([], 'Xfile.o') + set suffixes= + call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e Xfile Xfile.c Xfile.o', @:) + set suffixes=.c + call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e Xfile Xfile.o Xfile.c', @:) + set suffixes=,, + call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e Xfile.c Xfile.o Xfile', @:) + set suffixes& + call delete('Xfile') + call delete('Xfile.c') + call delete('Xfile.o') +endfunc + " Test for using a popup menu for the command line completion matches " (wildoptions=pum) func Test_wildmenu_pum() diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index b464f6591d..0f2066b7c1 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -2454,6 +2454,7 @@ endfunc func Test_glob() call assert_equal('', glob(v:_null_string)) call assert_equal('', globpath(v:_null_string, v:_null_string)) + call assert_fails("let x = globpath(&rtp, 'syntax/c.vim', [])", 'E745:') call writefile([], 'Xglob1') call writefile([], 'XGLOB2') diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index 30bbd355df..f9f7c5b492 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -1279,4 +1279,19 @@ func Test_progname() call delete('Xprogname', 'd') endfunc +" Test for doing a write from .vimrc +func Test_write_in_vimrc() + call writefile(['silent! write'], 'Xvimrc') + let after =<< trim [CODE] + call assert_match('E32: ', v:errmsg) + call writefile(v:errors, 'Xtestout') + qall + [CODE] + if RunVim([], after, '-u Xvimrc') + call assert_equal([], readfile('Xtestout')) + call delete('Xtestout') + endif + call delete('Xvimrc') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index a7ebe8cde6..81615b5963 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -57,7 +57,29 @@ func Test_writefile_fails_conversion() call assert_fails('write ++enc=cp932', 'E513:') call assert_equal(contents, readfile('Xfile')) + " With 'backupcopy' set, if there is a conversion error, the backup file is + " still created. + set backupcopy=yes writebackup& backup& + call delete('Xfile' .. &backupext) + call assert_fails('write ++enc=cp932', 'E513:') + call assert_equal(contents, readfile('Xfile')) + call assert_equal(contents, readfile('Xfile' .. &backupext)) + set backupcopy& + %bw! + + " Conversion error during write + new + call setline(1, ["\U10000000"]) + let output = execute('write! ++enc=utf-16 Xfile') + call assert_match('CONVERSION ERROR', output) + let output = execute('write! ++enc=ucs-2 Xfile') + call assert_match('CONVERSION ERROR', output) + call delete('Xfilz~') + call delete('Xfily~') + %bw! + call delete('Xfile') + call delete('Xfile' .. &backupext) bwipe! set backup& writebackup& backupdir&vim backupskip&vim endfunc @@ -270,6 +292,16 @@ func Test_write_errors() let long_fname = repeat('n', 5000) call assert_fails('exe "w " .. long_fname', 'E75:') call assert_fails('call writefile([], long_fname)', 'E482:') + + " Test for writing to a block device on Unix-like systems + if has('unix') && getfperm('/dev/loop0') != '' + \ && getftype('/dev/loop0') == 'bdev' && !IsRoot() + new + edit /dev/loop0 + call assert_fails('write', 'E503: ') + call assert_fails('write!', 'E503: ') + close! + endif endfunc " Test for writing to a file which is modified after Vim read it @@ -396,8 +428,21 @@ func Test_write_readonly() call setline(1, ['line1']) write! call assert_equal(['line1'], readfile('Xfile')) + + " Auto-saving a readonly file should fail with 'autowriteall' + %bw! + e Xfile + set noreadonly autowriteall + call setline(1, ['aaaa']) + call assert_fails('n', 'E505:') + set cpo+=W + call assert_fails('n', 'E504:') + set cpo-=W + set autowriteall& + set backupskip& call delete('Xfile') + %bw! endfunc " Test for 'patchmode' @@ -413,6 +458,19 @@ func Test_patchmode() " subsequent writes should not create/modify the .orig file write call assert_equal(['one'], readfile('Xfile.orig')) + + " use 'patchmode' with 'nobackup' and 'nowritebackup' to create an empty + " original file + call delete('Xfile') + call delete('Xfile.orig') + %bw! + set patchmode=.orig nobackup nowritebackup + edit Xfile + call setline(1, ['xxx']) + write + call assert_equal(['xxx'], readfile('Xfile')) + call assert_equal([], readfile('Xfile.orig')) + set patchmode& backup& backupskip& writebackup& call delete('Xfile') call delete('Xfile.orig') @@ -426,7 +484,7 @@ func Test_write_readonly_dir() " Root can do it too. CheckNotRoot - call mkdir('Xdir') + call mkdir('Xdir/') call writefile(['one'], 'Xdir/Xfile1') call setfperm('Xdir', 'r-xr--r--') " try to create a new file in the directory @@ -710,10 +768,167 @@ func Test_read_write_bin() call assert_equal(0z6E6F656F6C0A, readfile('XNoEolSetEol', 'B')) call delete('XNoEolSetEol') - set ff& + set ff& fixeol& bwipe! XNoEolSetEol endfunc +" Test for the 'backupcopy' option when writing files +func Test_backupcopy() + CheckUnix + set backupskip= + " With the default 'backupcopy' setting, saving a symbolic link file + " should not break the link. + set backupcopy& + call writefile(['1111'], 'Xfile1') + silent !ln -s Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['2222'], readfile('Xfile1')) + call assert_equal('Xfile1', resolve('Xfile2')) + call assert_equal('link', getftype('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + + " With the 'backupcopy' set to 'breaksymlink', saving a symbolic link file + " should break the link. + set backupcopy=yes,breaksymlink + call writefile(['1111'], 'Xfile1') + silent !ln -s Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['1111'], readfile('Xfile1')) + call assert_equal(['2222'], readfile('Xfile2')) + call assert_equal('Xfile2', resolve('Xfile2')) + call assert_equal('file', getftype('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + set backupcopy& + + " With the default 'backupcopy' setting, saving a hard link file + " should not break the link. + set backupcopy& + call writefile(['1111'], 'Xfile1') + silent !ln Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['2222'], readfile('Xfile1')) + call delete('Xfile1') + call delete('Xfile2') + + " With the 'backupcopy' set to 'breaksymlink', saving a hard link file + " should break the link. + set backupcopy=yes,breakhardlink + call writefile(['1111'], 'Xfile1') + silent !ln Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + call assert_equal(['1111'], readfile('Xfile1')) + call assert_equal(['2222'], readfile('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + + " If a backup file is already present, then a slightly modified filename + " should be used as the backup file. Try with 'backupcopy' set to 'yes' and + " 'no'. + %bw + call writefile(['aaaa'], 'Xfile') + call writefile(['bbbb'], 'Xfile.bak') + set backupcopy=yes backupext=.bak + new Xfile + call setline(1, ['cccc']) + write + close + call assert_equal(['cccc'], readfile('Xfile')) + call assert_equal(['bbbb'], readfile('Xfile.bak')) + set backupcopy=no backupext=.bak + new Xfile + call setline(1, ['dddd']) + write + close + call assert_equal(['dddd'], readfile('Xfile')) + call assert_equal(['bbbb'], readfile('Xfile.bak')) + call delete('Xfile') + call delete('Xfile.bak') + + " Write to a device file (in Unix-like systems) which cannot be backed up. + if has('unix') + set writebackup backupcopy=yes nobackup + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + set writebackup backupcopy=no nobackup + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + set backup writebackup& backupcopy& + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + endif + + set backupcopy& backupskip& backupext& backup& +endfunc + +" Test for writing a file with 'encoding' set to 'utf-16' +func Test_write_utf16() + new + call setline(1, ["\U00010001"]) + write ++enc=utf-16 Xfile + bw! + call assert_equal(0zD800DC01, readfile('Xfile', 'B')[0:3]) + call delete('Xfile') +endfunc + +" Test for trying to save a backup file when the backup file is a symbolic +" link to the original file. The backup file should not be modified. +func Test_write_backup_symlink() + CheckUnix + call writefile(['1111'], 'Xfile') + silent !ln -s Xfile Xfile.bak + + new Xfile + set backup backupcopy=yes backupext=.bak + write + call assert_equal('link', getftype('Xfile.bak')) + call assert_equal('Xfile', resolve('Xfile.bak')) + set backup& backupcopy& backupext& + close + + call delete('Xfile') + call delete('Xfile.bak') +endfunc + +" Test for ':write ++bin' and ':write ++nobin' +func Test_write_binary_file() + " create a file without an eol/eof character + call writefile(0z616161, 'Xfile1', 'b') + new Xfile1 + write ++bin Xfile2 + write ++nobin Xfile3 + call assert_equal(0z616161, readblob('Xfile2')) + if has('win32') + call assert_equal(0z6161610D.0A, readblob('Xfile3')) + else + call assert_equal(0z6161610A, readblob('Xfile3')) + endif + call delete('Xfile1') + call delete('Xfile2') + call delete('Xfile3') +endfunc + " Check that buffer is written before triggering QuitPre func Test_wq_quitpre_autocommand() edit Xsomefile |