diff options
-rw-r--r-- | src/nvim/eval.c | 34 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 10 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 93 | ||||
-rw-r--r-- | src/nvim/pos.h | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_assert.vim | 174 | ||||
-rw-r--r-- | src/nvim/testdir/test_cdo.vim | 205 | ||||
-rw-r--r-- | src/nvim/testdir/test_cursor_func.vim | 67 | ||||
-rw-r--r-- | src/nvim/testdir/test_options.vim | 37 | ||||
-rw-r--r-- | src/nvim/testdir/test_packadd.vim | 361 | ||||
-rw-r--r-- | src/nvim/testdir/test_retab.vim | 21 | ||||
-rw-r--r-- | test/functional/legacy/assert_spec.lua | 233 | ||||
-rw-r--r-- | test/functional/legacy/cdo_spec.lua | 228 | ||||
-rw-r--r-- | test/functional/legacy/packadd_spec.lua | 507 |
15 files changed, 983 insertions, 997 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4b83bda804..07f0799bc4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8192,7 +8192,7 @@ char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl) /// Convert the specified byte index of line 'lnum' in buffer 'buf' to a /// character index. Works only for loaded buffers. Returns -1 on failure. -/// The index of the first character is one. +/// The index of the first byte and the first character is zero. int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx) { if (buf == NULL || buf->b_ml.ml_mfp == NULL) { @@ -8206,15 +8206,29 @@ int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx) char_u *str = ml_get_buf(buf, lnum, false); if (*str == NUL) { - return 1; + return 0; + } + + // count the number of characters + char_u *t = str; + int count; + for (count = 0; *t != NUL && t <= str + byteidx; count++) { + t += utfc_ptr2len(t); + } + + // In insert mode, when the cursor is at the end of a non-empty line, + // byteidx points to the NUL character immediately past the end of the + // string. In this case, add one to the character count. + if (*t == NUL && byteidx != 0 && t == str + byteidx) { + count++; } - return mb_charlen_len(str, byteidx + 1); + return count - 1; } /// Convert the specified character index of line 'lnum' in buffer 'buf' to a -/// byte index. Works only for loaded buffers. Returns -1 on failure. The index -/// of the first byte and the first character is one. +/// byte index. Works only for loaded buffers. Returns -1 on failure. +/// The index of the first byte and the first character is zero. int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx) { if (buf == NULL || buf->b_ml.ml_mfp == NULL) { @@ -8233,7 +8247,7 @@ int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx) t += utfc_ptr2len(t); } - return t - str + 1; + return t - str; } /// Translate a VimL object into a position @@ -8315,7 +8329,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (name[0] == '.') { // Cursor. pos = curwin->w_cursor; if (charcol) { - pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1; + pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col); } return &pos; } @@ -8326,7 +8340,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret pos = curwin->w_cursor; } if (charcol) { - pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1; + pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col); } return &pos; } @@ -8336,7 +8350,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret return NULL; } if (charcol) { - pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col) - 1; + pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col); } return pp; } @@ -8423,7 +8437,7 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c if (buf == NULL || buf->b_ml.ml_mfp == NULL) { return FAIL; } - n = buf_charidx_to_byteidx(buf, posp->lnum, n); + n = buf_charidx_to_byteidx(buf, posp->lnum, n) + 1; } posp->col = n; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8beacc9988..7772d9ffc2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1588,7 +1588,7 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) line = tv_get_lnum(argvars); col = (long)tv_get_number_chk(&argvars[1], NULL); if (charcol) { - col = buf_charidx_to_byteidx(curbuf, line, col); + col = buf_charidx_to_byteidx(curbuf, line, col) + 1; } if (argvars[2].v_type != VAR_UNKNOWN) { coladd = (long)tv_get_number_chk(&argvars[2], NULL); @@ -3327,7 +3327,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos, bool } if (fp != NULL && charcol) { pos = *fp; - pos.col = buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col) - 1; + pos.col = buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col); fp = &pos; } } else { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index fd1e34803f..49bf9972b1 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -814,7 +814,11 @@ void ex_retab(exarg_T *eap) // len is actual number of white characters used len = num_spaces + num_tabs; old_len = (long)STRLEN(ptr); - long new_len = old_len - col + start_col + len + 1; + const long new_len = old_len - col + start_col + len + 1; + if (new_len <= 0 || new_len >= MAXCOL) { + emsg(_(e_resulting_text_too_long)); + break; + } new_line = xmalloc(new_len); if (start_col > 0) { @@ -847,6 +851,10 @@ void ex_retab(exarg_T *eap) break; } vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); + if (vcol >= MAXCOL) { + emsg(_(e_resulting_text_too_long)); + break; + } col += utfc_ptr2len(ptr + col); } if (new_line == NULL) { // out of memory diff --git a/src/nvim/globals.h b/src/nvim/globals.h index f6fbe98ff0..98a38c5fe2 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1000,6 +1000,8 @@ EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string req EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); +EXTERN char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); + EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); diff --git a/src/nvim/option.c b/src/nvim/option.c index df5f352258..c8e50d4494 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6232,6 +6232,9 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_fcs = vim_strsave(from->wo_fcs); to->wo_lcs = vim_strsave(from->wo_lcs); to->wo_winbl = from->wo_winbl; + + // Copy the script context so that we know were the value was last set. + memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx)); check_winopt(to); // don't want NULL pointers } @@ -6304,11 +6307,30 @@ void didset_window_options(win_T *wp) wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } +/// Index into the options table for a buffer-local option enum. +static int buf_opt_idx[BV_COUNT]; +#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set + +/// Initialize buf_opt_idx[] if not done already. +static void init_buf_opt_idx(void) +{ + static int did_init_buf_opt_idx = false; + + if (did_init_buf_opt_idx) { + return; + } + did_init_buf_opt_idx = true; + for (int i = 0; options[i].fullname != NULL; i++) { + if (options[i].indir & PV_BUF) { + buf_opt_idx[options[i].indir & PV_MASK] = i; + } + } +} /// Copy global option values to local options for one buffer. /// Used when creating a new buffer and sometimes when entering a buffer. /// flags: -/// BCO_ENTER We will enter the buf buffer. +/// BCO_ENTER We will enter the buffer "buf". /// BCO_ALWAYS Always copy the options, but only set b_p_initialized when /// appropriate. /// BCO_NOHELP Don't copy the values to a help buffer. @@ -6344,11 +6366,12 @@ void buf_copy_options(buf_T *buf, int flags) } if (should_copy || (flags & BCO_ALWAYS)) { - /* Don't copy the options specific to a help buffer when - * BCO_NOHELP is given or the options were initialized already - * (jumping back to a help file with CTRL-T or CTRL-O) */ - dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) - || buf->b_p_initialized; + memset(buf->b_p_script_ctx, 0, sizeof(buf->b_p_script_ctx)); + init_buf_opt_idx(); + // Don't copy the options specific to a help buffer when + // BCO_NOHELP is given or the options were initialized already + // (jumping back to a help file with CTRL-T or CTRL-O) + dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; if (dont_do_help) { // don't free b_p_isk save_p_isk = buf->b_p_isk; buf->b_p_isk = NULL; @@ -6380,35 +6403,58 @@ void buf_copy_options(buf_T *buf, int flags) } buf->b_p_ai = p_ai; + COPY_OPT_SCTX(buf, BV_AI); buf->b_p_ai_nopaste = p_ai_nopaste; buf->b_p_sw = p_sw; + COPY_OPT_SCTX(buf, BV_SW); buf->b_p_scbk = p_scbk; + COPY_OPT_SCTX(buf, BV_SCBK); buf->b_p_tw = p_tw; + COPY_OPT_SCTX(buf, BV_TW); buf->b_p_tw_nopaste = p_tw_nopaste; buf->b_p_tw_nobin = p_tw_nobin; buf->b_p_wm = p_wm; + COPY_OPT_SCTX(buf, BV_WM); buf->b_p_wm_nopaste = p_wm_nopaste; buf->b_p_wm_nobin = p_wm_nobin; buf->b_p_bin = p_bin; + COPY_OPT_SCTX(buf, BV_BIN); buf->b_p_bomb = p_bomb; + COPY_OPT_SCTX(buf, BV_BOMB); buf->b_p_et = p_et; + COPY_OPT_SCTX(buf, BV_ET); buf->b_p_fixeol = p_fixeol; + COPY_OPT_SCTX(buf, BV_FIXEOL); buf->b_p_et_nobin = p_et_nobin; buf->b_p_et_nopaste = p_et_nopaste; buf->b_p_ml = p_ml; + COPY_OPT_SCTX(buf, BV_ML); buf->b_p_ml_nobin = p_ml_nobin; buf->b_p_inf = p_inf; - buf->b_p_swf = cmdmod.noswapfile ? false : p_swf; + COPY_OPT_SCTX(buf, BV_INF); + if (cmdmod.noswapfile) { + buf->b_p_swf = false; + } else { + buf->b_p_swf = p_swf; + COPY_OPT_SCTX(buf, BV_SWF); + } buf->b_p_cpt = vim_strsave(p_cpt); + COPY_OPT_SCTX(buf, BV_CPT); #ifdef BACKSLASH_IN_FILENAME buf->b_p_csl = vim_strsave(p_csl); + COPY_OPT_SCTX(buf, BV_CSL); #endif buf->b_p_cfu = vim_strsave(p_cfu); + COPY_OPT_SCTX(buf, BV_CFU); buf->b_p_ofu = vim_strsave(p_ofu); + COPY_OPT_SCTX(buf, BV_OFU); buf->b_p_tfu = vim_strsave(p_tfu); + COPY_OPT_SCTX(buf, BV_TFU); buf->b_p_sts = p_sts; + COPY_OPT_SCTX(buf, BV_STS); buf->b_p_sts_nopaste = p_sts_nopaste; buf->b_p_vsts = vim_strsave(p_vsts); + COPY_OPT_SCTX(buf, BV_VSTS); if (p_vsts && p_vsts != empty_option) { (void)tabstop_set(p_vsts, &buf->b_p_vsts_array); } else { @@ -6418,42 +6464,68 @@ void buf_copy_options(buf_T *buf, int flags) ? vim_strsave(p_vsts_nopaste) : NULL; buf->b_p_com = vim_strsave(p_com); + COPY_OPT_SCTX(buf, BV_COM); buf->b_p_cms = vim_strsave(p_cms); + COPY_OPT_SCTX(buf, BV_CMS); buf->b_p_fo = vim_strsave(p_fo); + COPY_OPT_SCTX(buf, BV_FO); buf->b_p_flp = vim_strsave(p_flp); + COPY_OPT_SCTX(buf, BV_FLP); buf->b_p_nf = vim_strsave(p_nf); + COPY_OPT_SCTX(buf, BV_NF); buf->b_p_mps = vim_strsave(p_mps); + COPY_OPT_SCTX(buf, BV_MPS); buf->b_p_si = p_si; + COPY_OPT_SCTX(buf, BV_SI); buf->b_p_channel = 0; buf->b_p_ci = p_ci; + COPY_OPT_SCTX(buf, BV_CI); buf->b_p_cin = p_cin; + COPY_OPT_SCTX(buf, BV_CIN); buf->b_p_cink = vim_strsave(p_cink); + COPY_OPT_SCTX(buf, BV_CINK); buf->b_p_cino = vim_strsave(p_cino); + COPY_OPT_SCTX(buf, BV_CINO); // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_option; buf->b_p_pi = p_pi; + COPY_OPT_SCTX(buf, BV_PI); buf->b_p_cinw = vim_strsave(p_cinw); + COPY_OPT_SCTX(buf, BV_CINW); buf->b_p_lisp = p_lisp; + COPY_OPT_SCTX(buf, BV_LISP); // Don't copy 'syntax', it must be set buf->b_p_syn = empty_option; buf->b_p_smc = p_smc; + COPY_OPT_SCTX(buf, BV_SMC); buf->b_s.b_syn_isk = empty_option; buf->b_s.b_p_spc = vim_strsave(p_spc); + COPY_OPT_SCTX(buf, BV_SPC); (void)compile_cap_prog(&buf->b_s); buf->b_s.b_p_spf = vim_strsave(p_spf); + COPY_OPT_SCTX(buf, BV_SPF); buf->b_s.b_p_spl = vim_strsave(p_spl); + COPY_OPT_SCTX(buf, BV_SPL); buf->b_s.b_p_spo = vim_strsave(p_spo); + COPY_OPT_SCTX(buf, BV_SPO); buf->b_p_inde = vim_strsave(p_inde); + COPY_OPT_SCTX(buf, BV_INDE); buf->b_p_indk = vim_strsave(p_indk); + COPY_OPT_SCTX(buf, BV_INDK); buf->b_p_fp = empty_option; buf->b_p_fex = vim_strsave(p_fex); + COPY_OPT_SCTX(buf, BV_FEX); buf->b_p_sua = vim_strsave(p_sua); + COPY_OPT_SCTX(buf, BV_SUA); buf->b_p_keymap = vim_strsave(p_keymap); + COPY_OPT_SCTX(buf, BV_KMAP); buf->b_kmap_state |= KEYMAP_INIT; // This isn't really an option, but copying the langmap and IME // state from the current buffer is better than resetting it. buf->b_p_iminsert = p_iminsert; + COPY_OPT_SCTX(buf, BV_IMI); buf->b_p_imsearch = p_imsearch; + COPY_OPT_SCTX(buf, BV_IMS); // options that are normally global but also have a local value // are not copied, start using the global value @@ -6473,11 +6545,14 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_def = empty_option; buf->b_p_inc = empty_option; buf->b_p_inex = vim_strsave(p_inex); + COPY_OPT_SCTX(buf, BV_INEX); buf->b_p_dict = empty_option; buf->b_p_tsr = empty_option; buf->b_p_tsrfu = empty_option; buf->b_p_qe = vim_strsave(p_qe); + COPY_OPT_SCTX(buf, BV_QE); buf->b_p_udf = p_udf; + COPY_OPT_SCTX(buf, BV_UDF); buf->b_p_lw = empty_option; buf->b_p_menc = empty_option; @@ -6496,9 +6571,12 @@ void buf_copy_options(buf_T *buf, int flags) } } else { buf->b_p_isk = vim_strsave(p_isk); + COPY_OPT_SCTX(buf, BV_ISK); did_isk = true; buf->b_p_ts = p_ts; + COPY_OPT_SCTX(buf, BV_TS); buf->b_p_vts = vim_strsave(p_vts); + COPY_OPT_SCTX(buf, BV_VTS); if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { (void)tabstop_set(p_vts, &buf->b_p_vts_array); } else { @@ -6509,6 +6587,7 @@ void buf_copy_options(buf_T *buf, int flags) clear_string_option(&buf->b_p_bt); } buf->b_p_ma = p_ma; + COPY_OPT_SCTX(buf, BV_MA); } } diff --git a/src/nvim/pos.h b/src/nvim/pos.h index d17e27906e..51991ed314 100644 --- a/src/nvim/pos.h +++ b/src/nvim/pos.h @@ -16,7 +16,9 @@ typedef int colnr_T; /// Maximal (invalid) line number enum { MAXLNUM = 0x7fffffff, }; /// Maximal column number -enum { MAXCOL = INT_MAX, }; +/// MAXCOL used to be INT_MAX, but with 64 bit ints that results in running +/// out of memory when trying to allocate a very long line. +enum { MAXCOL = 0x7fffffff, }; // Minimum line number enum { MINLNUM = 1, }; // minimum column number diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim index 52f243aaea..28c5948142 100644 --- a/src/nvim/testdir/test_assert.vim +++ b/src/nvim/testdir/test_assert.vim @@ -1,5 +1,55 @@ " Test that the methods used for testing work. +func Test_assert_false() + call assert_equal(0, assert_false(0)) + call assert_equal(0, assert_false(v:false)) + call assert_equal(0, v:false->assert_false()) + + call assert_equal(1, assert_false(123)) + call assert_match("Expected False but got 123", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, 123->assert_false()) + call assert_match("Expected False but got 123", v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_assert_true() + call assert_equal(0, assert_true(1)) + call assert_equal(0, assert_true(123)) + call assert_equal(0, assert_true(v:true)) + call assert_equal(0, v:true->assert_true()) + + call assert_equal(1, assert_true(0)) + call assert_match("Expected True but got 0", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, 0->assert_true()) + call assert_match("Expected True but got 0", v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_assert_equal() + let s = 'foo' + call assert_equal(0, assert_equal('foo', s)) + let n = 4 + call assert_equal(0, assert_equal(4, n)) + let l = [1, 2, 3] + call assert_equal(0, assert_equal([1, 2, 3], l)) + call assert_equal(v:_null_list, v:_null_list) + call assert_equal(v:_null_list, []) + call assert_equal([], v:_null_list) + + let s = 'foo' + call assert_equal(1, assert_equal('bar', s)) + call assert_match("Expected 'bar' but got 'foo'", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX') + call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0]) + call remove(v:errors, 0) +endfunc + func Test_assert_equalfile() call assert_equal(1, assert_equalfile('abcabc', 'xyzxyz')) call assert_match("E485: Can't read file abcabc", v:errors[0]) @@ -46,17 +96,129 @@ func Test_assert_equalfile() call delete('Xtwo') endfunc +func Test_assert_notequal() + let n = 4 + call assert_equal(0, assert_notequal('foo', n)) + let s = 'foo' + call assert_equal(0, assert_notequal([1, 2, 3], s)) + + call assert_equal(1, assert_notequal('foo', s)) + call assert_match("Expected not equal to 'foo'", v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_assert_report() + call assert_equal(1, assert_report('something is wrong')) + call assert_match('something is wrong', v:errors[0]) + call remove(v:errors, 0) + call assert_equal(1, 'also wrong'->assert_report()) + call assert_match('also wrong', v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_assert_exception() + try + nocommand + catch + call assert_equal(0, assert_exception('E492:')) + endtry + + try + nocommand + catch + try + " illegal argument, get NULL for error + call assert_equal(1, assert_exception([])) + catch + call assert_equal(0, assert_exception('E730:')) + endtry + endtry +endfunc + +func Test_wrong_error_type() + let save_verrors = v:errors + let v:['errors'] = {'foo': 3} + call assert_equal('yes', 'no') + let verrors = v:errors + let v:errors = save_verrors + call assert_equal(type([]), type(verrors)) +endfunc + +func Test_match() + call assert_equal(0, assert_match('^f.*b.*r$', 'foobar')) + + call assert_equal(1, assert_match('bar.*foo', 'foobar')) + call assert_match("Pattern 'bar.*foo' does not match 'foobar'", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, assert_match('bar.*foo', 'foobar', 'wrong')) + call assert_match('wrong', v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong')) + call assert_match('wrong', v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_notmatch() + call assert_equal(0, assert_notmatch('foo', 'bar')) + call assert_equal(0, assert_notmatch('^foobar$', 'foobars')) + + call assert_equal(1, assert_notmatch('foo', 'foobar')) + call assert_match("Pattern 'foo' does match 'foobar'", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, 'foobar'->assert_notmatch('foo')) + call assert_match("Pattern 'foo' does match 'foobar'", v:errors[0]) + call remove(v:errors, 0) +endfunc + +func Test_assert_fail_fails() + call assert_equal(1, assert_fails('xxx', 'E12345')) + call assert_match("Expected 'E12345' but got 'E492:", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, assert_fails('xxx', 'E9876', 'stupid')) + call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, assert_fails('echo', '', 'echo command')) + call assert_match("command did not fail: echo command", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(1, 'echo'->assert_fails('', 'echo command')) + call assert_match("command did not fail: echo command", v:errors[0]) + call remove(v:errors, 0) +endfunc + func Test_assert_fails_in_try_block() try call assert_equal(0, assert_fails('throw "error"')) endtry endfunc +func Test_assert_beeps() + new + call assert_equal(0, assert_beeps('normal h')) + + call assert_equal(1, assert_beeps('normal 0')) + call assert_match("command did not beep: normal 0", v:errors[0]) + call remove(v:errors, 0) + + call assert_equal(0, 'normal h'->assert_beeps()) + call assert_equal(1, 'normal 0'->assert_beeps()) + call assert_match("command did not beep: normal 0", v:errors[0]) + call remove(v:errors, 0) + + bwipe +endfunc + func Test_assert_inrange() call assert_equal(0, assert_inrange(7, 7, 7)) call assert_equal(0, assert_inrange(5, 7, 5)) call assert_equal(0, assert_inrange(5, 7, 6)) call assert_equal(0, assert_inrange(5, 7, 7)) + call assert_equal(1, assert_inrange(5, 7, 4)) call assert_match("Expected range 5 - 7, but got 4", v:errors[0]) call remove(v:errors, 0) @@ -64,6 +226,12 @@ func Test_assert_inrange() call assert_match("Expected range 5 - 7, but got 8", v:errors[0]) call remove(v:errors, 0) + call assert_equal(0, 5->assert_inrange(5, 7)) + call assert_equal(0, 7->assert_inrange(5, 7)) + call assert_equal(1, 8->assert_inrange(5, 7)) + call assert_match("Expected range 5 - 7, but got 8", v:errors[0]) + call remove(v:errors, 0) + call assert_fails('call assert_inrange(1, 1)', 'E119:') if has('float') @@ -83,6 +251,12 @@ func Test_assert_inrange() endif endfunc +func Test_assert_with_msg() + call assert_equal('foo', 'bar', 'testing') + call assert_match("testing: Expected 'foo' but got 'bar'", v:errors[0]) + call remove(v:errors, 0) +endfunc + " Must be last. func Test_zz_quit_detected() " Verify that if a test function ends Vim the test script detects this. diff --git a/src/nvim/testdir/test_cdo.vim b/src/nvim/testdir/test_cdo.vim new file mode 100644 index 0000000000..aa2e4f1a8c --- /dev/null +++ b/src/nvim/testdir/test_cdo.vim @@ -0,0 +1,205 @@ +" Tests for the :cdo, :cfdo, :ldo and :lfdo commands + +if !has('quickfix') + throw 'Skipped: quickfix feature missing' +endif + +" Create the files used by the tests +function SetUp() + call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1') + call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2') + call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3') +endfunction + +" Remove the files used by the tests +function TearDown() + call delete('Xtestfile1') + call delete('Xtestfile2') + call delete('Xtestfile3') +endfunction + +" Returns the current line in '<filename> <linenum>L <column>C' format +function GetRuler() + return expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' +endfunction + +" Tests for the :cdo and :ldo commands +function XdoTests(cchar) + enew + + " Shortcuts for calling the cdo and ldo commands + let Xdo = a:cchar . 'do' + let Xgetexpr = a:cchar . 'getexpr' + let Xprev = a:cchar. 'prev' + let XdoCmd = Xdo . ' call add(l, GetRuler())' + + " Try with an empty list + let l = [] + exe XdoCmd + call assert_equal([], l) + + " Populate the list and then try + exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']" + + let l = [] + exe XdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) + + " Run command only on selected error lines + let l = [] + enew + exe "2,3" . XdoCmd + call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) + + " Boundary condition tests + let l = [] + enew + exe "1,1" . XdoCmd + call assert_equal(['Xtestfile1 1L 3C'], l) + + let l = [] + enew + exe "3" . XdoCmd + call assert_equal(['Xtestfile3 3L 1C'], l) + + " Range test commands + let l = [] + enew + exe "%" . XdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) + + let l = [] + enew + exe "1,$" . XdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) + + let l = [] + enew + exe Xprev + exe "." . XdoCmd + call assert_equal(['Xtestfile2 2L 2C'], l) + + let l = [] + enew + exe "+" . XdoCmd + call assert_equal(['Xtestfile3 3L 1C'], l) + + " Invalid error lines test + let l = [] + enew + exe "silent! 27" . XdoCmd + exe "silent! 4,5" . XdoCmd + call assert_equal([], l) + + " Run commands from an unsaved buffer + let v:errmsg='' + let l = [] + enew + setlocal modified + exe "silent! 2,2" . XdoCmd + if v:errmsg !~# 'No write since last change' + call add(v:errors, 'Unsaved file change test failed') + endif + + " If the executed command fails, then the operation should be aborted + enew! + let subst_count = 0 + exe "silent!" . Xdo . " s/Line/xLine/ | let subst_count += 1" + if subst_count != 1 || getline('.') != 'xLine1' + call add(v:errors, 'Abort command on error test failed') + endif + + let l = [] + exe "2,2" . Xdo . "! call add(l, GetRuler())" + call assert_equal(['Xtestfile2 2L 2C'], l) + + " List with no valid error entries + let l = [] + edit! +2 Xtestfile1 + exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + exe XdoCmd + call assert_equal([], l) + exe "silent! 2" . XdoCmd + call assert_equal([], l) + let v:errmsg='' + exe "%" . XdoCmd + exe "1,$" . XdoCmd + exe "." . XdoCmd + call assert_equal('', v:errmsg) + + " List with only one valid entry + let l = [] + exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" + exe XdoCmd + call assert_equal(['Xtestfile3 3L 1C'], l) + +endfunction + +" Tests for the :cfdo and :lfdo commands +function XfdoTests(cchar) + enew + + " Shortcuts for calling the cfdo and lfdo commands + let Xfdo = a:cchar . 'fdo' + let Xgetexpr = a:cchar . 'getexpr' + let XfdoCmd = Xfdo . ' call add(l, GetRuler())' + let Xpfile = a:cchar. 'pfile' + + " Clear the quickfix/location list + exe Xgetexpr . " []" + + " Try with an empty list + let l = [] + exe XfdoCmd + call assert_equal([], l) + + " Populate the list and then try + exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']" + + let l = [] + exe XfdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) + + " Run command only on selected error lines + let l = [] + exe "2,3" . XfdoCmd + call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) + + " Boundary condition tests + let l = [] + exe "3" . XfdoCmd + call assert_equal(['Xtestfile3 2L 3C'], l) + + " Range test commands + let l = [] + exe "%" . XfdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) + + let l = [] + exe "1,$" . XfdoCmd + call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) + + let l = [] + exe Xpfile + exe "." . XfdoCmd + call assert_equal(['Xtestfile2 2L 2C'], l) + + " List with only one valid entry + let l = [] + exe Xgetexpr . " ['Xtestfile2:2:5:Line2']" + exe XfdoCmd + call assert_equal(['Xtestfile2 2L 5C'], l) + +endfunction + +" Tests for cdo and cfdo +function Test_cdo() + call XdoTests('c') + call XfdoTests('c') +endfunction + +" Tests for ldo and lfdo +function Test_ldo() + call XdoTests('l') + call XfdoTests('l') +endfunction diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim index 47e74a24d6..57825b4551 100644 --- a/src/nvim/testdir/test_cursor_func.vim +++ b/src/nvim/testdir/test_cursor_func.vim @@ -123,11 +123,18 @@ func Test_screenpos_number() bwipe! endfunc +" Save the visual start character position func SaveVisualStartCharPos() call add(g:VisualStartPos, getcharpos('v')) return '' endfunc +" Save the current cursor character position in insert mode +func SaveInsertCurrentCharPos() + call add(g:InsertCurrentPos, getcharpos('.')) + return '' +endfunc + " Test for the getcharpos() function func Test_getcharpos() call assert_fails('call getcharpos({})', 'E731:') @@ -156,16 +163,29 @@ func Test_getcharpos() vnoremap <expr> <F3> SaveVisualStartCharPos() let g:VisualStartPos = [] exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>" - call assert_equal([[0, 2, 7, 0], [0, 2, 9, 0], [0, 2, 5, 0]], g:VisualStartPos) + call assert_equal([[0, 2, 7, 0], [0, 2, 10, 0], [0, 2, 5, 0]], g:VisualStartPos) call assert_equal([0, 2, 9, 0], getcharpos('v')) let g:VisualStartPos = [] exe "normal 3Gv$\<F3>o\<F3>" - call assert_equal([[0, 3, 1, 0], [0, 3, 1, 0]], g:VisualStartPos) + call assert_equal([[0, 3, 1, 0], [0, 3, 2, 0]], g:VisualStartPos) let g:VisualStartPos = [] exe "normal 1Gv$\<F3>o\<F3>" call assert_equal([[0, 1, 1, 0], [0, 1, 1, 0]], g:VisualStartPos) vunmap <F3> + " Test for getting the position in insert mode with the cursor after the + " last character in a line + inoremap <expr> <F3> SaveInsertCurrentCharPos() + let g:InsertCurrentPos = [] + exe "normal 1GA\<F3>" + exe "normal 2GA\<F3>" + exe "normal 3GA\<F3>" + exe "normal 4GA\<F3>" + exe "normal 2G6li\<F3>" + call assert_equal([[0, 1, 1, 0], [0, 2, 10, 0], [0, 3, 2, 0], [0, 4, 10, 0], + \ [0, 2, 7, 0]], g:InsertCurrentPos) + iunmap <F3> + %bw! endfunc @@ -192,6 +212,10 @@ func Test_setcharpos() call setcharpos("'m", [0, 2, 9, 0]) normal `m call assert_equal([2, 11], [line('.'), col('.')]) + " unload the buffer and try to set the mark + let bnr = bufnr() + enew! + call assert_equal(-1, setcharpos("'m", [bnr, 2, 2, 0])) %bw! call assert_equal(-1, setcharpos('.', [10, 3, 1, 0])) @@ -202,6 +226,11 @@ func SaveVisualStartCharCol() return '' endfunc +func SaveInsertCurrentCharCol() + call add(g:InsertCurrentCol, charcol('.')) + return '' +endfunc + " Test for the charcol() function func Test_charcol() call assert_fails('call charcol({})', 'E731:') @@ -239,19 +268,36 @@ func Test_charcol() vnoremap <expr> <F3> SaveVisualStartCharCol() let g:VisualStartCol = [] exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>" - call assert_equal([7, 9, 5], g:VisualStartCol) + call assert_equal([7, 10, 5], g:VisualStartCol) call assert_equal(9, charcol('v')) let g:VisualStartCol = [] exe "normal 3Gv$\<F3>o\<F3>" - call assert_equal([1, 1], g:VisualStartCol) + call assert_equal([1, 2], g:VisualStartCol) let g:VisualStartCol = [] exe "normal 1Gv$\<F3>o\<F3>" call assert_equal([1, 1], g:VisualStartCol) vunmap <F3> + " Test for getting the column number in insert mode with the cursor after + " the last character in a line + inoremap <expr> <F3> SaveInsertCurrentCharCol() + let g:InsertCurrentCol = [] + exe "normal 1GA\<F3>" + exe "normal 2GA\<F3>" + exe "normal 3GA\<F3>" + exe "normal 4GA\<F3>" + exe "normal 2G6li\<F3>" + call assert_equal([1, 10, 2, 10, 7], g:InsertCurrentCol) + iunmap <F3> + %bw! endfunc +func SaveInsertCursorCharPos() + call add(g:InsertCursorPos, getcursorcharpos('.')) + return '' +endfunc + " Test for getcursorcharpos() func Test_getcursorcharpos() call assert_equal(getcursorcharpos(), getcursorcharpos(0)) @@ -269,6 +315,19 @@ func Test_getcursorcharpos() normal 4G9l call assert_equal([0, 4, 9, 0, 9], getcursorcharpos()) + " Test for getting the cursor position in insert mode with the cursor after + " the last character in a line + inoremap <expr> <F3> SaveInsertCursorCharPos() + let g:InsertCursorPos = [] + exe "normal 1GA\<F3>" + exe "normal 2GA\<F3>" + exe "normal 3GA\<F3>" + exe "normal 4GA\<F3>" + exe "normal 2G6li\<F3>" + call assert_equal([[0, 1, 1, 0, 1], [0, 2, 10, 0, 15], [0, 3, 2, 0, 2], + \ [0, 4, 10, 0, 10], [0, 2, 7, 0, 12]], g:InsertCursorPos) + iunmap <F3> + let winid = win_getid() normal 2G5l wincmd w diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 7d1fed3b94..8612b7013b 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -314,21 +314,50 @@ func Test_set_errors() set modifiable& endfunc +func CheckWasSet(name) + let verb_cm = execute('verbose set ' .. a:name .. '?') + call assert_match('Last set from.*test_options.vim', verb_cm) +endfunc +func CheckWasNotSet(name) + let verb_cm = execute('verbose set ' .. a:name .. '?') + call assert_notmatch('Last set from', verb_cm) +endfunc + " Must be executed before other tests that set 'term'. func Test_000_term_option_verbose() if has('nvim') || has('gui_running') return endif - let verb_cm = execute('verbose set t_cm') - call assert_notmatch('Last set from', verb_cm) + + call CheckWasNotSet('t_cm') let term_save = &term set term=ansi - let verb_cm = execute('verbose set t_cm') - call assert_match('Last set from.*test_options.vim', verb_cm) + call CheckWasSet('t_cm') let &term = term_save endfunc +func Test_copy_context() + setlocal list + call CheckWasSet('list') + split + call CheckWasSet('list') + quit + setlocal nolist + + set ai + call CheckWasSet('ai') + set filetype=perl + call CheckWasSet('filetype') + set fo=tcroq + call CheckWasSet('fo') + + split Xsomebuf + call CheckWasSet('ai') + call CheckWasNotSet('filetype') + call CheckWasSet('fo') +endfunc + func Test_set_ttytype() " Nvim does not support 'ttytype'. if !has('nvim') && !has('gui_running') && has('unix') diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim new file mode 100644 index 0000000000..fcb8b8033b --- /dev/null +++ b/src/nvim/testdir/test_packadd.vim @@ -0,0 +1,361 @@ +" Tests for 'packpath' and :packadd + + +func SetUp() + let s:topdir = getcwd() . '/Xdir' + exe 'set packpath=' . s:topdir + let s:plugdir = s:topdir . '/pack/mine/opt/mytest' +endfunc + +func TearDown() + call delete(s:topdir, 'rf') +endfunc + +func Test_packadd() + if !exists('s:plugdir') + echomsg 'when running this test manually, call SetUp() first' + return + endif + + call mkdir(s:plugdir . '/plugin/also', 'p') + call mkdir(s:plugdir . '/ftdetect', 'p') + call mkdir(s:plugdir . '/after', 'p') + set rtp& + let rtp = &rtp + filetype on + + let rtp_entries = split(rtp, ',') + for entry in rtp_entries + if entry =~? '\<after\>' + let first_after_entry = entry + break + endif + endfor + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 42') + wq + + exe 'split ' . s:plugdir . '/plugin/also/loaded.vim' + call setline(1, 'let g:plugin_also_works = 77') + wq + + exe 'split ' . s:plugdir . '/ftdetect/test.vim' + call setline(1, 'let g:ftdetect_works = 17') + wq + + packadd mytest + + call assert_equal(42, g:plugin_works) + call assert_equal(77, g:plugin_also_works) + call assert_equal(17, g:ftdetect_works) + call assert_true(len(&rtp) > len(rtp)) + call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp) + + let new_after = match(&rtp, '/testdir/Xdir/pack/mine/opt/mytest/after,') + let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g') + let old_after = match(&rtp, ',' . forwarded . '\>') + call assert_true(new_after > 0, 'rtp is ' . &rtp) + call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp) + call assert_true(new_after < old_after, 'rtp is ' . &rtp) + + " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest' + call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p') + let rtp = &rtp + packadd myte + + " Check the path of 'myte' is added + call assert_true(len(&rtp) > len(rtp)) + call assert_match('/testdir/Xdir/pack/mine/opt/myte\($\|,\)', &rtp) + + " Check exception + call assert_fails("packadd directorynotfound", 'E919:') + call assert_fails("packadd", 'E471:') +endfunc + +func Test_packadd_start() + let plugdir = s:topdir . '/pack/mine/start/other' + call mkdir(plugdir . '/plugin', 'p') + set rtp& + let rtp = &rtp + filetype on + + exe 'split ' . plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 24') + wq + + packadd other + + call assert_equal(24, g:plugin_works) + call assert_true(len(&rtp) > len(rtp)) + call assert_match('/testdir/Xdir/pack/mine/start/other\($\|,\)', &rtp) +endfunc + +func Test_packadd_noload() + call mkdir(s:plugdir . '/plugin', 'p') + call mkdir(s:plugdir . '/syntax', 'p') + set rtp& + let rtp = &rtp + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 42') + wq + let g:plugin_works = 0 + + packadd! mytest + + call assert_true(len(&rtp) > len(rtp)) + call assert_match('testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp) + call assert_equal(0, g:plugin_works) + + " check the path is not added twice + let new_rtp = &rtp + packadd! mytest + call assert_equal(new_rtp, &rtp) +endfunc + +func Test_packadd_symlink_dir() + if !has('unix') + return + endif + let top2_dir = s:topdir . '/Xdir2' + let real_dir = s:topdir . '/Xsym' + call mkdir(real_dir, 'p') + exec "silent !ln -s Xsym" top2_dir + let &rtp = top2_dir . ',' . top2_dir . '/after' + let &packpath = &rtp + + let s:plugdir = top2_dir . '/pack/mine/opt/mytest' + call mkdir(s:plugdir . '/plugin', 'p') + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 44') + wq + let g:plugin_works = 0 + + packadd mytest + + " Must have been inserted in the middle, not at the end + call assert_match('/pack/mine/opt/mytest,', &rtp) + call assert_equal(44, g:plugin_works) + + " No change when doing it again. + let rtp_before = &rtp + packadd mytest + call assert_equal(rtp_before, &rtp) + + set rtp& + let rtp = &rtp + exec "silent !rm" top2_dir +endfunc + +func Test_packadd_symlink_dir2() + if !has('unix') + return + endif + let top2_dir = s:topdir . '/Xdir2' + let real_dir = s:topdir . '/Xsym/pack' + call mkdir(top2_dir, 'p') + call mkdir(real_dir, 'p') + let &rtp = top2_dir . ',' . top2_dir . '/after' + let &packpath = &rtp + + exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack' + let s:plugdir = top2_dir . '/pack/mine/opt/mytest' + call mkdir(s:plugdir . '/plugin', 'p') + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 48') + wq + let g:plugin_works = 0 + + packadd mytest + + " Must have been inserted in the middle, not at the end + call assert_match('/Xdir2/pack/mine/opt/mytest,', &rtp) + call assert_equal(48, g:plugin_works) + + " No change when doing it again. + let rtp_before = &rtp + packadd mytest + call assert_equal(rtp_before, &rtp) + + set rtp& + let rtp = &rtp + exec "silent !rm" top2_dir . '/pack' + exec "silent !rmdir" top2_dir +endfunc + +" Check command-line completion for 'packadd' +func Test_packadd_completion() + let optdir1 = &packpath . '/pack/mine/opt' + let optdir2 = &packpath . '/pack/candidate/opt' + + call mkdir(optdir1 . '/pluginA', 'p') + call mkdir(optdir1 . '/pluginC', 'p') + call mkdir(optdir2 . '/pluginB', 'p') + call mkdir(optdir2 . '/pluginC', 'p') + + let li = [] + call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":packadd " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":packadd " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":packadd " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx') + call assert_equal("packadd pluginA", li[0]) + call assert_equal("packadd pluginB", li[1]) + call assert_equal("packadd pluginC", li[2]) + call assert_equal("packadd ", li[3]) +endfunc + +func Test_packloadall() + " plugin foo with an autoload directory + let fooplugindir = &packpath . '/pack/mine/start/foo/plugin' + call mkdir(fooplugindir, 'p') + call writefile(['let g:plugin_foo_number = 1234', + \ 'let g:plugin_foo_auto = bbb#value', + \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim') + let fooautodir = &packpath . '/pack/mine/start/foo/autoload' + call mkdir(fooautodir, 'p') + call writefile(['let bar#value = 77'], fooautodir . '/bar.vim') + + " plugin aaa with an autoload directory + let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin' + call mkdir(aaaplugindir, 'p') + call writefile(['let g:plugin_aaa_number = 333', + \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim') + let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload' + call mkdir(aaaautodir, 'p') + call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim') + + " plugin extra with only an autoload directory + let extraautodir = &packpath . '/pack/mine/start/extra/autoload' + call mkdir(extraautodir, 'p') + call writefile(['let extra#value = 99'], extraautodir . '/extra.vim') + + packloadall + call assert_equal(1234, g:plugin_foo_number) + call assert_equal(55, g:plugin_foo_auto) + call assert_equal(99, g:plugin_extra_auto) + call assert_equal(333, g:plugin_aaa_number) + call assert_equal(77, g:plugin_aaa_auto) + + " only works once + call writefile(['let g:plugin_bar_number = 4321'], fooplugindir . '/bar2.vim') + packloadall + call assert_false(exists('g:plugin_bar_number')) + + " works when ! used + packloadall! + call assert_equal(4321, g:plugin_bar_number) +endfunc + +func Test_helptags() + let docdir1 = &packpath . '/pack/mine/start/foo/doc' + let docdir2 = &packpath . '/pack/mine/start/bar/doc' + call mkdir(docdir1, 'p') + call mkdir(docdir2, 'p') + call writefile(['look here: *look-here*'], docdir1 . '/bar.txt') + call writefile(['look away: *look-away*'], docdir2 . '/foo.txt') + exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar' + + helptags ALL + + let tags1 = readfile(docdir1 . '/tags') + call assert_match('look-here', tags1[0]) + let tags2 = readfile(docdir2 . '/tags') + call assert_match('look-away', tags2[0]) + + call assert_fails('helptags abcxyz', 'E150:') +endfunc + +func Test_colorscheme() + let colordirrun = &packpath . '/runtime/colors' + let colordirstart = &packpath . '/pack/mine/start/foo/colors' + let colordiropt = &packpath . '/pack/mine/opt/bar/colors' + call mkdir(colordirrun, 'p') + call mkdir(colordirstart, 'p') + call mkdir(colordiropt, 'p') + call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') + call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') + call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') + exe 'set rtp=' . &packpath . '/runtime' + + colorscheme one + call assert_equal(1, g:found_one) + colorscheme two + call assert_equal(1, g:found_two) + colorscheme three + call assert_equal(1, g:found_three) +endfunc + +func Test_colorscheme_completion() + let colordirrun = &packpath . '/runtime/colors' + let colordirstart = &packpath . '/pack/mine/start/foo/colors' + let colordiropt = &packpath . '/pack/mine/opt/bar/colors' + call mkdir(colordirrun, 'p') + call mkdir(colordirstart, 'p') + call mkdir(colordiropt, 'p') + call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') + call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') + call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') + exe 'set rtp=' . &packpath . '/runtime' + + let li=[] + call feedkeys(":colorscheme " . repeat("\<Tab>", 1) . "')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":colorscheme " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":colorscheme " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't') + call feedkeys(":colorscheme " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx') + call assert_equal("colorscheme one", li[0]) + call assert_equal("colorscheme three", li[1]) + call assert_equal("colorscheme two", li[2]) + call assert_equal("colorscheme ", li[3]) +endfunc + +func Test_runtime() + let rundir = &packpath . '/runtime/extra' + let startdir = &packpath . '/pack/mine/start/foo/extra' + let optdir = &packpath . '/pack/mine/opt/bar/extra' + call mkdir(rundir, 'p') + call mkdir(startdir, 'p') + call mkdir(optdir, 'p') + call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim') + call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim') + call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim') + call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim') + call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim') + exe 'set rtp=' . &packpath . '/runtime' + + let g:sequence = '' + runtime extra/bar.vim + call assert_equal('run', g:sequence) + let g:sequence = '' + runtime START extra/bar.vim + call assert_equal('start', g:sequence) + let g:sequence = '' + runtime OPT extra/bar.vim + call assert_equal('opt', g:sequence) + let g:sequence = '' + runtime PACK extra/bar.vim + call assert_equal('start', g:sequence) + let g:sequence = '' + runtime! PACK extra/bar.vim + call assert_equal('startopt', g:sequence) + let g:sequence = '' + runtime PACK extra/xxx.vim + call assert_equal('xxxopt', g:sequence) + + let g:sequence = '' + runtime ALL extra/bar.vim + call assert_equal('run', g:sequence) + let g:sequence = '' + runtime ALL extra/foo.vim + call assert_equal('foostart', g:sequence) + let g:sequence = '' + runtime! ALL extra/xxx.vim + call assert_equal('xxxopt', g:sequence) + let g:sequence = '' + runtime! ALL extra/bar.vim + call assert_equal('runstartopt', g:sequence) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_retab.vim b/src/nvim/testdir/test_retab.vim index e7b8946ccf..1650a03876 100644 --- a/src/nvim/testdir/test_retab.vim +++ b/src/nvim/testdir/test_retab.vim @@ -69,6 +69,8 @@ func Test_retab() call assert_equal(" a b c ", Retab('!', 3)) call assert_equal(" a b c ", Retab('', 5)) call assert_equal(" a b c ", Retab('!', 5)) + + set tabstop& expandtab& endfunc func Test_retab_error() @@ -78,3 +80,22 @@ func Test_retab_error() call assert_fails('ret 10000', 'E475:') call assert_fails('ret 80000000000000000000', 'E475:') endfunc + +func Test_retab_endless() + new + call setline(1, "\t0\t") + let caught = 'no' + try + while 1 + set ts=4000 + retab 4 + endwhile + catch /E1240/ + let caught = 'yes' + endtry + bwipe! + set tabstop& +endfunc + + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index c2b22472bf..dd6a9d0bde 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -19,36 +19,10 @@ describe('assert function:', function() clear() end) - describe('assert_beeps', function() - it('works', function() - call('assert_beeps', 'normal h') - expected_empty() - call('assert_beeps', 'normal 0') - expected_errors({'command did not beep: normal 0'}) - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(0, 'normal h'->assert_beeps()) - call assert_equal(1, 'normal 0'->assert_beeps()) - ]] - expected_errors({tmpname .. ' line 2: command did not beep: normal 0'}) - end) - end) - -- assert_equal({expected}, {actual}, [, {msg}]) describe('assert_equal', function() it('should not change v:errors when expected is equal to actual', function() source([[ - let s = 'foo' - call assert_equal('foo', s) - let n = 4 - call assert_equal(4, n) - let l = [1, 2, 3] - call assert_equal([1, 2, 3], l) - call assert_equal(v:_null_list, v:_null_list) - call assert_equal(v:_null_list, []) - call assert_equal([], v:_null_list) fu Func() endfu let F1 = function('Func') @@ -98,30 +72,6 @@ describe('assert function:', function() eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', exc_exec('call CheckAssert()')) end) - - it('can specify a message and get a message about what failed', function() - call('assert_equal', 'foo', 'bar', 'testing') - expected_errors({"testing: Expected 'foo' but got 'bar'"}) - end) - - it('should shorten a long message', function() - call ('assert_equal', 'XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX') - expected_errors({"Expected 'X\\[x occurs 21 times]X' but got 'X\\[y occurs 25 times]X'"}) - end) - end) - - -- assert_notequal({expected}, {actual}[, {msg}]) - describe('assert_notequal', function() - it('should not change v:errors when expected differs from actual', function() - eq(0, call('assert_notequal', 'foo', 4)) - eq(0, call('assert_notequal', {1, 2, 3}, 'foo')) - expected_empty() - end) - - it('should change v:errors when expected is equal to actual', function() - eq(1, call('assert_notequal', 'foo', 'foo')) - expected_errors({"Expected not equal to 'foo'"}) - end) end) -- assert_false({actual}, [, {msg}]) @@ -141,14 +91,6 @@ describe('assert function:', function() call('assert_false', {}) expected_errors({'Expected False but got []'}) end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(0, v:false->assert_false()) - call assert_equal(1, 123->assert_false()) - ]] - expected_errors({tmpname .. ' line 2: Expected False but got 123'}) - end) end) -- assert_true({actual}, [, {msg}]) @@ -164,14 +106,6 @@ describe('assert function:', function() eq(1, call('assert_true', 1.5)) expected_errors({'Expected True but got 1.5'}) end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(0, v:true->assert_true()) - call assert_equal(1, 0->assert_true()) - ]] - expected_errors({tmpname .. ' line 2: Expected True but got 0'}) - end) end) describe('v:errors', function() @@ -217,76 +151,10 @@ describe('assert function:', function() tmpname_two .. " line 1: file two: Expected True but got ''", }) end) - - it('is reset to a list by assert functions', function() - source([[ - let save_verrors = v:errors - let v:['errors'] = {'foo': 3} - call assert_equal('yes', 'no') - let verrors = v:errors - let v:errors = save_verrors - call assert_equal(type([]), type(verrors)) - ]]) - expected_empty() - end) - end) - - -- assert_match({pat}, {text}[, {msg}]) - describe('assert_match', function() - it('should not change v:errors when pat matches text', function() - call('assert_match', '^f.*b.*r$', 'foobar') - expected_empty() - end) - - it('should change v:errors when pat does not match text', function() - call('assert_match', 'bar.*foo', 'foobar') - expected_errors({"Pattern 'bar.*foo' does not match 'foobar'"}) - end) - - it('should set v:errors to msg when given and match fails', function() - call('assert_match', 'bar.*foo', 'foobar', 'wrong') - expected_errors({"wrong: Pattern 'bar.*foo' does not match 'foobar'"}) - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong')) - ]] - expected_errors({ - tmpname .. " line 1: wrong: Pattern 'bar.*foo' does not match 'foobar'" - }) - end) - end) - - -- assert_notmatch({pat}, {text}[, {msg}]) - describe('assert_notmatch', function() - it('should not change v:errors when pat does not match text', function() - call('assert_notmatch', 'foo', 'bar') - call('assert_notmatch', '^foobar$', 'foobars') - expected_empty() - end) - - it('should change v:errors when pat matches text', function() - call('assert_notmatch', 'foo', 'foobar') - expected_errors({"Pattern 'foo' does match 'foobar'"}) - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(1, 'foobar'->assert_notmatch('foo')) - ]] - expected_errors({tmpname .. " line 1: Pattern 'foo' does match 'foobar'"}) - end) end) -- assert_fails({cmd}, [, {error}]) describe('assert_fails', function() - it('should change v:errors when error does not match v:errmsg', function() - eq(1, eval([[assert_fails('xxx', 'E12345')]])) - command([[call assert_match("Expected 'E12345' but got 'E492:", v:errors[0])]]) - expected_errors({"Expected 'E12345' but got 'E492: Not an editor command: xxx': xxx"}) - end) - it('should not change v:errors when cmd errors', function() eq(0, eval([[assert_fails('NonexistentCmd')]])) expected_empty() @@ -296,106 +164,5 @@ describe('assert function:', function() eq(1, eval([[assert_fails('call empty("")', '')]])) expected_errors({'command did not fail: call empty("")'}) end) - - it('can specify and get a message about what failed', function() - eq(1, eval([[assert_fails('xxx', 'E9876', 'stupid')]])) - command([[call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])]]) - expected_errors({"stupid: Expected 'E9876' but got 'E492: Not an editor command: xxx': stupid"}) - end) - - it('can specify and get a message even when cmd succeeds', function() - eq(1, eval([[assert_fails('echo', '', 'echo command')]])) - expected_errors({'command did not fail: echo command'}) - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(1, 'echo'->assert_fails('', 'echo command')) - ]] - expected_errors({ - tmpname .. ' line 1: command did not fail: echo command' - }) - end) - end) - - -- assert_inrange({lower}, {upper}, {actual}[, {msg}]) - describe('assert_inrange()', function() - it('should not change v:errors when actual is in range', function() - call('assert_inrange', 7, 7, 7) - call('assert_inrange', 5, 7, 5) - call('assert_inrange', 5, 7, 6) - call('assert_inrange', 5, 7, 7) - expected_empty() - end) - - it('should change v:errors when actual is not in range', function() - call('assert_inrange', 5, 7, 4) - call('assert_inrange', 5, 7, 8) - expected_errors({ - "Expected range 5 - 7, but got 4", - "Expected range 5 - 7, but got 8", - }) - end) - - it('assert_inrange(1, 1) returns E119', function() - eq('Vim(call):E119: Not enough arguments for function: assert_inrange', - exc_exec("call assert_inrange(1, 1)")) - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(0, 5->assert_inrange(5, 7)) - call assert_equal(0, 7->assert_inrange(5, 7)) - call assert_equal(1, 8->assert_inrange(5, 7)) - ]] - expected_errors({tmpname .. ' line 3: Expected range 5 - 7, but got 8'}) - end) - end) - - -- assert_report({msg}) - describe('assert_report()', function() - it('should add a message to v:errors', function() - eq(1, call('assert_report', 'something is wrong')) - command("call assert_match('something is wrong', v:errors[0])") - command('call remove(v:errors, 0)') - expected_empty() - end) - - it('can be used as a method', function() - local tmpname = source [[ - call assert_equal(1, 'also wrong'->assert_report()) - ]] - expected_errors({tmpname .. ' line 1: also wrong'}) - end) - end) - - -- assert_exception({cmd}, [, {error}]) - describe('assert_exception()', function() - it('should assert thrown exceptions properly', function() - source([[ - try - nocommand - catch - call assert_equal(0, assert_exception('E492')) - endtry - ]]) - expected_empty() - end) - - it('should work properly when nested', function() - source([[ - try - nocommand - catch - try - " illegal argument, get NULL for error - call assert_equal(1, assert_exception([])) - catch - call assert_equal(0, assert_exception('E730')) - endtry - endtry - ]]) - expected_empty() - end) end) end) diff --git a/test/functional/legacy/cdo_spec.lua b/test/functional/legacy/cdo_spec.lua deleted file mode 100644 index 8b3216cbfd..0000000000 --- a/test/functional/legacy/cdo_spec.lua +++ /dev/null @@ -1,228 +0,0 @@ --- Tests for the :cdo, :cfdo, :ldo and :lfdo commands - -local helpers = require('test.functional.helpers')(after_each) -local nvim, clear = helpers.meths, helpers.clear -local call, feed = helpers.call, helpers.feed -local source, eq = helpers.source, helpers.eq - -local function expected_empty() - eq({}, nvim.get_vvar('errors')) -end - -describe('cdo', function() - before_each(function() - clear() - - call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile1') - call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile2') - call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile3') - - source([=[ - " Returns the current line in '<filename> <linenum>L <column>C' format - function GetRuler() - return expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' - endfunction - - " Tests for the :cdo and :ldo commands - function XdoTests(cchar) - enew - - " Shortcuts for calling the cdo and ldo commands - let Xdo = a:cchar . 'do' - let Xgetexpr = a:cchar . 'getexpr' - let Xprev = a:cchar. 'prev' - let XdoCmd = Xdo . ' call add(l, GetRuler())' - - " Try with an empty list - let l = [] - exe XdoCmd - call assert_equal([], l) - - " Populate the list and then try - exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']" - - let l = [] - exe XdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) - - " Run command only on selected error lines - let l = [] - enew - exe "2,3" . XdoCmd - call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) - - " Boundary condition tests - let l = [] - enew - exe "1,1" . XdoCmd - call assert_equal(['Xtestfile1 1L 3C'], l) - - let l = [] - enew - exe "3" . XdoCmd - call assert_equal(['Xtestfile3 3L 1C'], l) - - " Range test commands - let l = [] - enew - exe "%" . XdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) - - let l = [] - enew - exe "1,$" . XdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l) - - let l = [] - enew - exe Xprev - exe "." . XdoCmd - call assert_equal(['Xtestfile2 2L 2C'], l) - - let l = [] - enew - exe "+" . XdoCmd - call assert_equal(['Xtestfile3 3L 1C'], l) - - " Invalid error lines test - let l = [] - enew - exe "silent! 27" . XdoCmd - exe "silent! 4,5" . XdoCmd - call assert_equal([], l) - - " Run commands from an unsaved buffer when 'hidden' is unset - set nohidden - let v:errmsg='' - let l = [] - enew - setlocal modified - exe "silent! 2,2" . XdoCmd - if v:errmsg !~# 'No write since last change' - call add(v:errors, 'Unsaved file change test failed') - endif - - " If the executed command fails, then the operation should be aborted - enew! - let subst_count = 0 - exe "silent!" . Xdo . " s/Line/xLine/ | let subst_count += 1" - if subst_count != 1 || getline('.') != 'xLine1' - call add(v:errors, 'Abort command on error test failed') - endif - set hidden - - let l = [] - exe "2,2" . Xdo . "! call add(l, GetRuler())" - call assert_equal(['Xtestfile2 2L 2C'], l) - - " List with no valid error entries - let l = [] - edit! +2 Xtestfile1 - exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" - exe XdoCmd - call assert_equal([], l) - exe "silent! 2" . XdoCmd - call assert_equal([], l) - let v:errmsg='' - exe "%" . XdoCmd - exe "1,$" . XdoCmd - exe "." . XdoCmd - call assert_equal('', v:errmsg) - - " List with only one valid entry - let l = [] - exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" - exe XdoCmd - call assert_equal(['Xtestfile3 3L 1C'], l) - - endfunction - - " Tests for the :cfdo and :lfdo commands - function XfdoTests(cchar) - enew - - " Shortcuts for calling the cfdo and lfdo commands - let Xfdo = a:cchar . 'fdo' - let Xgetexpr = a:cchar . 'getexpr' - let XfdoCmd = Xfdo . ' call add(l, GetRuler())' - let Xpfile = a:cchar. 'pfile' - - " Clear the quickfix/location list - exe Xgetexpr . " []" - - " Try with an empty list - let l = [] - exe XfdoCmd - call assert_equal([], l) - - " Populate the list and then try - exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']" - - let l = [] - exe XfdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) - - " Run command only on selected error lines - let l = [] - exe "2,3" . XfdoCmd - call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) - - " Boundary condition tests - let l = [] - exe "3" . XfdoCmd - call assert_equal(['Xtestfile3 2L 3C'], l) - - " Range test commands - let l = [] - exe "%" . XfdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) - - let l = [] - exe "1,$" . XfdoCmd - call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l) - - let l = [] - exe Xpfile - exe "." . XfdoCmd - call assert_equal(['Xtestfile2 2L 2C'], l) - - " List with only one valid entry - let l = [] - exe Xgetexpr . " ['Xtestfile2:2:5:Line2']" - exe XfdoCmd - call assert_equal(['Xtestfile2 2L 5C'], l) - - endfunction - ]=]) - end) - - after_each(function() - os.remove('Xtestfile1') - os.remove('Xtestfile2') - os.remove('Xtestfile3') - end) - - it('works for :cdo', function() - -- call('XdoTests', 'c') - feed(":call XdoTests('c')<CR><C-l>") - expected_empty() - end) - - it('works for :cfdo', function() - -- call('XfdoTests', 'c') - feed(":call XfdoTests('c')<CR><C-l>") - expected_empty() - end) - - it('works for :ldo', function() - -- call('XdoTests', 'l') - feed(":call XdoTests('l')<CR><C-l>") - expected_empty() - end) - - it('works for :lfdo', function() - -- call('XfdoTests', 'l') - feed(":call XfdoTests('l')<CR><C-l>") - expected_empty() - end) -end) diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua deleted file mode 100644 index 4f9f5a0237..0000000000 --- a/test/functional/legacy/packadd_spec.lua +++ /dev/null @@ -1,507 +0,0 @@ --- Tests for 'packpath' and :packadd - -local helpers = require('test.functional.helpers')(after_each) -local clear, source, command = helpers.clear, helpers.source, helpers.command -local call, eq, nvim = helpers.call, helpers.eq, helpers.meths -local feed = helpers.feed - -local function expected_empty() - eq({}, nvim.get_vvar('errors')) -end - -describe('packadd', function() - before_each(function() - clear() - - source([=[ - func Escape(s) - return escape(a:s, '\~') - endfunc - - func SetUp() - let s:topdir = expand(getcwd() . '/Xdir') - if isdirectory(s:topdir) - call delete(s:topdir, 'rf') - endif - exe 'set packpath=' . s:topdir - let s:plugdir = expand(s:topdir . '/pack/mine/opt/mytest') - endfunc - - func TearDown() - call delete(s:topdir, 'rf') - endfunc - - func Test_packadd() - if !exists('s:plugdir') - echomsg 'when running this test manually, call SetUp() first' - return - endif - - call mkdir(s:plugdir . '/plugin/also', 'p') - call mkdir(s:plugdir . '/ftdetect', 'p') - call mkdir(s:plugdir . '/after', 'p') - set rtp& - let rtp = &rtp - filetype on - - let rtp_entries = split(rtp, ',') - for entry in rtp_entries - if entry =~? '\<after\>' - let first_after_entry = entry - break - endif - endfor - - exe 'split ' . s:plugdir . '/plugin/test.vim' - call setline(1, 'let g:plugin_works = 42') - wq - - exe 'split ' . s:plugdir . '/plugin/also/loaded.vim' - call setline(1, 'let g:plugin_also_works = 77') - wq - - exe 'split ' . s:plugdir . '/ftdetect/test.vim' - call setline(1, 'let g:ftdetect_works = 17') - wq - - packadd mytest - - call assert_true(42, g:plugin_works) - call assert_equal(77, g:plugin_also_works) - call assert_true(17, g:ftdetect_works) - call assert_true(len(&rtp) > len(rtp)) - call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) - - let new_after = match(&rtp, Escape(expand(s:plugdir . '/after') . ',')) - let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g') - let old_after = match(&rtp, ',' . escape(forwarded, '~') . '\>') - call assert_true(new_after > 0, 'rtp is ' . &rtp) - call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp) - call assert_true(new_after < old_after, 'rtp is ' . &rtp) - - " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest' - call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p') - let rtp = &rtp - packadd myte - - " Check the path of 'myte' is added - call assert_true(len(&rtp) > len(rtp)) - call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) - - " Check exception - call assert_fails("packadd directorynotfound", 'E919:') - call assert_fails("packadd", 'E471:') - endfunc - - func Test_packadd_start() - let plugdir = expand(s:topdir . '/pack/mine/start/other') - call mkdir(plugdir . '/plugin', 'p') - set rtp& - let rtp = &rtp - filetype on - - exe 'split ' . plugdir . '/plugin/test.vim' - call setline(1, 'let g:plugin_works = 24') - wq - - exe 'split ' . plugdir . '/plugin/test.lua' - call setline(1, 'vim.g.plugin_lua_works = 24') - wq - - packadd other - - call assert_equal(24, g:plugin_works) - call assert_equal(24, g:plugin_lua_works) - call assert_true(len(&rtp) > len(rtp)) - call assert_match(Escape(plugdir) . '\($\|,\)', &rtp) - endfunc - - func Test_packadd_noload() - call mkdir(s:plugdir . '/plugin', 'p') - call mkdir(s:plugdir . '/syntax', 'p') - set rtp& - let rtp = &rtp - - exe 'split ' . s:plugdir . '/plugin/test.vim' - call setline(1, 'let g:plugin_works = 42') - wq - exe 'split ' . s:plugdir . '/plugin/test.lua' - call setline(1, 'let g:plugin_lua_works = 42') - wq - let g:plugin_works = 0 - let g:plugin_lua_works = 0 - - packadd! mytest - - call assert_true(len(&rtp) > len(rtp)) - call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) - call assert_equal(0, g:plugin_works) - call assert_equal(0, g:plugin_lua_works) - - " check the path is not added twice - let new_rtp = &rtp - packadd! mytest - call assert_equal(new_rtp, &rtp) - endfunc - - func Test_packadd_symlink_dir() - let top2_dir = expand(s:topdir . '/Xdir2') - let real_dir = expand(s:topdir . '/Xsym') - call mkdir(real_dir, 'p') - if has('win32') - exec "silent! !mklink /d" top2_dir "Xsym" - else - exec "silent! !ln -s Xsym" top2_dir - endif - let &rtp = top2_dir . ',' . expand(top2_dir . '/after') - let &packpath = &rtp - - let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest') - call mkdir(s:plugdir . '/plugin', 'p') - - exe 'split ' . s:plugdir . '/plugin/test.vim' - call setline(1, 'let g:plugin_works = 44') - wq - let g:plugin_works = 0 - - packadd mytest - - " Must have been inserted in the middle, not at the end - call assert_match(Escape(expand('/pack/mine/opt/mytest').','), &rtp) - call assert_equal(44, g:plugin_works) - - " No change when doing it again. - let rtp_before = &rtp - packadd mytest - call assert_equal(rtp_before, &rtp) - - set rtp& - let rtp = &rtp - exec "silent !" (has('win32') ? "rd /q/s" : "rm") top2_dir - endfunc - - func Test_packadd_symlink_dir2() - let top2_dir = expand(s:topdir . '/Xdir2') - let real_dir = expand(s:topdir . '/Xsym/pack') - call mkdir(top2_dir, 'p') - call mkdir(real_dir, 'p') - let &rtp = top2_dir . ',' . top2_dir . '/after' - let &packpath = &rtp - - if has('win32') - exec "silent! !mklink /d" top2_dir "Xsym" - else - exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack' - endif - let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest') - call mkdir(s:plugdir . '/plugin', 'p') - - exe 'split ' . s:plugdir . '/plugin/test.vim' - call setline(1, 'let g:plugin_works = 48') - wq - let g:plugin_works = 0 - - packadd mytest - - " Must have been inserted in the middle, not at the end - call assert_match(Escape(expand('/Xdir2/pack/mine/opt/mytest').','), &rtp) - call assert_equal(48, g:plugin_works) - - " No change when doing it again. - let rtp_before = &rtp - packadd mytest - call assert_equal(rtp_before, &rtp) - - set rtp& - let rtp = &rtp - if has('win32') - exec "silent !rd /q/s" top2_dir - else - exec "silent !rm" top2_dir . '/pack' - exec "silent !rmdir" top2_dir - endif - endfunc - - func Test_packloadall() - " plugin foo with an autoload directory - let fooplugindir = &packpath . '/pack/mine/start/foo/plugin' - call mkdir(fooplugindir, 'p') - call writefile(['let g:plugin_foo_number = 1234', - \ 'let g:plugin_foo_auto = bbb#value', - \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim') - let fooautodir = &packpath . '/pack/mine/start/foo/autoload' - call mkdir(fooautodir, 'p') - call writefile(['let bar#value = 77'], fooautodir . '/bar.vim') - - " plugin aaa with an autoload directory - let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin' - call mkdir(aaaplugindir, 'p') - call writefile(['let g:plugin_aaa_number = 333', - \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim') - let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload' - call mkdir(aaaautodir, 'p') - call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim') - - " plugin extra with only an autoload directory - let extraautodir = &packpath . '/pack/mine/start/extra/autoload' - call mkdir(extraautodir, 'p') - call writefile(['let extra#value = 99'], extraautodir . '/extra.vim') - - packloadall - call assert_equal(1234, g:plugin_foo_number) - call assert_equal(55, g:plugin_foo_auto) - call assert_equal(99, g:plugin_extra_auto) - call assert_equal(333, g:plugin_aaa_number) - call assert_equal(77, g:plugin_aaa_auto) - - " only works once - call writefile(['let g:plugin_bar_number = 4321'], - \ fooplugindir . '/bar2.vim') - packloadall - call assert_false(exists('g:plugin_bar_number')) - - " works when ! used - packloadall! - call assert_equal(4321, g:plugin_bar_number) - endfunc - - func Test_helptags() - let docdir1 = &packpath . '/pack/mine/start/foo/doc' - let docdir2 = &packpath . '/pack/mine/start/bar/doc' - call mkdir(docdir1, 'p') - call mkdir(docdir2, 'p') - call writefile(['look here: *look-here*'], docdir1 . '/bar.txt') - call writefile(['look away: *look-away*'], docdir2 . '/foo.txt') - exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar' - - helptags ALL - - let tags1 = readfile(docdir1 . '/tags') - call assert_match('look-here', tags1[0]) - let tags2 = readfile(docdir2 . '/tags') - call assert_match('look-away', tags2[0]) - - call assert_fails('helptags abcxyz', 'E150:') - endfunc - - func Test_colorscheme() - let colordirrun = &packpath . '/runtime/colors' - let colordirstart = &packpath . '/pack/mine/start/foo/colors' - let colordiropt = &packpath . '/pack/mine/opt/bar/colors' - call mkdir(colordirrun, 'p') - call mkdir(colordirstart, 'p') - call mkdir(colordiropt, 'p') - call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') - call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') - call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') - exe 'set rtp=' . &packpath . '/runtime' - - colorscheme one - call assert_equal(1, g:found_one) - colorscheme two - call assert_equal(1, g:found_two) - colorscheme three - call assert_equal(1, g:found_three) - endfunc - - func Test_runtime() - let rundir = &packpath . '/runtime/extra' - let startdir = &packpath . '/pack/mine/start/foo/extra' - let optdir = &packpath . '/pack/mine/opt/bar/extra' - call mkdir(rundir, 'p') - call mkdir(startdir, 'p') - call mkdir(optdir, 'p') - call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim') - call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim') - call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim') - call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim') - call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim') - exe 'set rtp=' . &packpath . '/runtime' - - let g:sequence = '' - runtime extra/bar.vim - call assert_equal('run', g:sequence) - let g:sequence = '' - runtime START extra/bar.vim - call assert_equal('start', g:sequence) - let g:sequence = '' - runtime OPT extra/bar.vim - call assert_equal('opt', g:sequence) - let g:sequence = '' - runtime PACK extra/bar.vim - call assert_equal('start', g:sequence) - let g:sequence = '' - runtime! PACK extra/bar.vim - call assert_equal('startopt', g:sequence) - let g:sequence = '' - runtime PACK extra/xxx.vim - call assert_equal('xxxopt', g:sequence) - - let g:sequence = '' - runtime ALL extra/bar.vim - call assert_equal('run', g:sequence) - let g:sequence = '' - runtime ALL extra/foo.vim - call assert_equal('foostart', g:sequence) - let g:sequence = '' - runtime! ALL extra/xxx.vim - call assert_equal('xxxopt', g:sequence) - let g:sequence = '' - runtime! ALL extra/bar.vim - call assert_equal('runstartopt', g:sequence) - endfunc - ]=]) - call('SetUp') - end) - - after_each(function() - call('TearDown') - end) - - it('is working', function() - call('Test_packadd') - expected_empty() - end) - - it('works with packadd!', function() - call('Test_packadd_noload') - expected_empty() - end) - - it('works with symlinks', function() - call('Test_packadd_symlink_dir') - expected_empty() - end) - - it('works with :packloadall', function() - call('Test_packloadall') - expected_empty() - end) - - it('works with helptags', function() - call('Test_helptags') - expected_empty() - end) - - it('works with colorschemes', function() - call('Test_colorscheme') - expected_empty() - end) - - it('works with :runtime [what]', function() - call('Test_runtime') - expected_empty() - end) - - it('loads packages from "start" directory', function() - call('Test_packadd_start') - expected_empty() - end) - - describe('command line completion', function() - local Screen = require('test.functional.ui.screen') - local screen - - before_each(function() - screen = Screen.new(30, 5) - screen:attach() - screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = { - foreground = Screen.colors.Black, - background = Screen.colors.Yellow, - }, - [2] = {bold = true, reverse = true} - }) - - command([[let optdir1 = &packpath . '/pack/mine/opt']]) - command([[let optdir2 = &packpath . '/pack/candidate/opt']]) - command([[call mkdir(optdir1 . '/pluginA', 'p')]]) - command([[call mkdir(optdir1 . '/pluginC', 'p')]]) - command([[call mkdir(optdir2 . '/pluginB', 'p')]]) - command([[call mkdir(optdir2 . '/pluginC', 'p')]]) - end) - - it('works', function() - feed(':packadd <Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {1:pluginA}{2: pluginB pluginC }| - :packadd pluginA^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:pluginA }{1:pluginB}{2: pluginC }| - :packadd pluginB^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:pluginA pluginB }{1:pluginC}{2: }| - :packadd pluginC^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:pluginA pluginB pluginC }| - :packadd ^ | - ]=]) - end) - - it('works for colorschemes', function() - source([[ - let colordirrun = &packpath . '/runtime/colors' - let colordirstart = &packpath . '/pack/mine/start/foo/colors' - let colordiropt = &packpath . '/pack/mine/opt/bar/colors' - call mkdir(colordirrun, 'p') - call mkdir(colordirstart, 'p') - call mkdir(colordiropt, 'p') - call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') - call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') - call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') - exe 'set rtp=' . &packpath . '/runtime']]) - - feed(':colorscheme <Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {1:one}{2: three two }| - :colorscheme one^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:one }{1:three}{2: two }| - :colorscheme three^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:one three }{1:two}{2: }| - :colorscheme two^ | - ]=]) - feed('<Tab>') - screen:expect([=[ - | - {0:~ }| - {0:~ }| - {2:one three two }| - :colorscheme ^ | - ]=]) - end) - end) -end) |