blob: 919b91182b8d4c64a22e28c3c36cc01f737ba346 [file] [log] [blame]
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * testing.c: Support for tests.
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17
18/*
19 * Prepare "gap" for an assert error and add the sourcing position.
20 */
21 static void
22prepare_assert_error(garray_T *gap)
23{
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010024 char buf[NUMBUFLEN];
Bram Moolenaar4f25b1a2020-09-10 19:25:05 +020025 char_u *sname = estack_sfile(ESTACK_NONE);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020026
27 ga_init2(gap, 1, 100);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010028 if (sname != NULL)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020029 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010030 ga_concat(gap, sname);
31 if (SOURCING_LNUM > 0)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020032 ga_concat(gap, (char_u *)" ");
33 }
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010034 if (SOURCING_LNUM > 0)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020035 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010036 sprintf(buf, "line %ld", (long)SOURCING_LNUM);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020037 ga_concat(gap, (char_u *)buf);
38 }
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010039 if (sname != NULL || SOURCING_LNUM > 0)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020040 ga_concat(gap, (char_u *)": ");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +010041 vim_free(sname);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020042}
43
44/*
45 * Append "p[clen]" to "gap", escaping unprintable characters.
46 * Changes NL to \n, CR to \r, etc.
47 */
48 static void
49ga_concat_esc(garray_T *gap, char_u *p, int clen)
50{
51 char_u buf[NUMBUFLEN];
52
53 if (clen > 1)
54 {
55 mch_memmove(buf, p, clen);
56 buf[clen] = NUL;
57 ga_concat(gap, buf);
58 }
59 else switch (*p)
60 {
61 case BS: ga_concat(gap, (char_u *)"\\b"); break;
62 case ESC: ga_concat(gap, (char_u *)"\\e"); break;
63 case FF: ga_concat(gap, (char_u *)"\\f"); break;
64 case NL: ga_concat(gap, (char_u *)"\\n"); break;
65 case TAB: ga_concat(gap, (char_u *)"\\t"); break;
66 case CAR: ga_concat(gap, (char_u *)"\\r"); break;
67 case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
68 default:
Bram Moolenaar7177da92020-07-12 23:09:20 +020069 if (*p < ' ' || *p == 0x7f)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +020070 {
71 vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
72 ga_concat(gap, buf);
73 }
74 else
75 ga_append(gap, *p);
76 break;
77 }
78}
79
80/*
81 * Append "str" to "gap", escaping unprintable characters.
82 * Changes NL to \n, CR to \r, etc.
83 */
84 static void
85ga_concat_shorten_esc(garray_T *gap, char_u *str)
86{
87 char_u *p;
88 char_u *s;
89 int c;
90 int clen;
91 char_u buf[NUMBUFLEN];
92 int same_len;
93
94 if (str == NULL)
95 {
96 ga_concat(gap, (char_u *)"NULL");
97 return;
98 }
99
100 for (p = str; *p != NUL; ++p)
101 {
102 same_len = 1;
103 s = p;
104 c = mb_ptr2char_adv(&s);
105 clen = s - p;
106 while (*s != NUL && c == mb_ptr2char(s))
107 {
108 ++same_len;
109 s += clen;
110 }
111 if (same_len > 20)
112 {
113 ga_concat(gap, (char_u *)"\\[");
114 ga_concat_esc(gap, p, clen);
115 ga_concat(gap, (char_u *)" occurs ");
116 vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len);
117 ga_concat(gap, buf);
118 ga_concat(gap, (char_u *)" times]");
119 p = s - 1;
120 }
121 else
122 ga_concat_esc(gap, p, clen);
123 }
124}
125
126/*
127 * Fill "gap" with information about an assert error.
128 */
129 static void
130fill_assert_error(
131 garray_T *gap,
132 typval_T *opt_msg_tv,
133 char_u *exp_str,
Bram Moolenaar4a021df2020-06-13 15:13:38 +0200134 typval_T *exp_tv_arg,
135 typval_T *got_tv_arg,
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200136 assert_type_T atype)
137{
138 char_u numbuf[NUMBUFLEN];
139 char_u *tofree;
Bram Moolenaar4a021df2020-06-13 15:13:38 +0200140 typval_T *exp_tv = exp_tv_arg;
141 typval_T *got_tv = got_tv_arg;
142 int did_copy = FALSE;
143 int omitted = 0;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200144
Bram Moolenaar1d634542020-08-18 13:41:50 +0200145 if (opt_msg_tv->v_type != VAR_UNKNOWN
146 && !(opt_msg_tv->v_type == VAR_STRING
147 && (opt_msg_tv->vval.v_string == NULL
148 || *opt_msg_tv->vval.v_string == NUL)))
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200149 {
150 ga_concat(gap, echo_string(opt_msg_tv, &tofree, numbuf, 0));
151 vim_free(tofree);
152 ga_concat(gap, (char_u *)": ");
153 }
154
155 if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH)
156 ga_concat(gap, (char_u *)"Pattern ");
157 else if (atype == ASSERT_NOTEQUAL)
158 ga_concat(gap, (char_u *)"Expected not equal to ");
159 else
160 ga_concat(gap, (char_u *)"Expected ");
161 if (exp_str == NULL)
162 {
Bram Moolenaar4a021df2020-06-13 15:13:38 +0200163 // When comparing dictionaries, drop the items that are equal, so that
164 // it's a lot easier to see what differs.
165 if (atype != ASSERT_NOTEQUAL
166 && exp_tv->v_type == VAR_DICT && got_tv->v_type == VAR_DICT
167 && exp_tv->vval.v_dict != NULL && got_tv->vval.v_dict != NULL)
168 {
169 dict_T *exp_d = exp_tv->vval.v_dict;
170 dict_T *got_d = got_tv->vval.v_dict;
171 hashitem_T *hi;
172 dictitem_T *item2;
173 int todo;
174
175 did_copy = TRUE;
176 exp_tv->vval.v_dict = dict_alloc();
177 got_tv->vval.v_dict = dict_alloc();
178 if (exp_tv->vval.v_dict == NULL || got_tv->vval.v_dict == NULL)
179 return;
180
181 todo = (int)exp_d->dv_hashtab.ht_used;
182 for (hi = exp_d->dv_hashtab.ht_array; todo > 0; ++hi)
183 {
184 if (!HASHITEM_EMPTY(hi))
185 {
186 item2 = dict_find(got_d, hi->hi_key, -1);
187 if (item2 == NULL || !tv_equal(&HI2DI(hi)->di_tv,
188 &item2->di_tv, FALSE, FALSE))
189 {
190 // item of exp_d not present in got_d or values differ.
191 dict_add_tv(exp_tv->vval.v_dict,
192 (char *)hi->hi_key, &HI2DI(hi)->di_tv);
193 if (item2 != NULL)
194 dict_add_tv(got_tv->vval.v_dict,
195 (char *)hi->hi_key, &item2->di_tv);
196 }
197 else
198 ++omitted;
199 --todo;
200 }
201 }
202
203 // Add items only present in got_d.
204 todo = (int)got_d->dv_hashtab.ht_used;
205 for (hi = got_d->dv_hashtab.ht_array; todo > 0; ++hi)
206 {
207 if (!HASHITEM_EMPTY(hi))
208 {
209 item2 = dict_find(exp_d, hi->hi_key, -1);
210 if (item2 == NULL)
211 // item of got_d not present in exp_d
212 dict_add_tv(got_tv->vval.v_dict,
213 (char *)hi->hi_key, &HI2DI(hi)->di_tv);
214 --todo;
215 }
216 }
217 }
218
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200219 ga_concat_shorten_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
220 vim_free(tofree);
221 }
222 else
223 ga_concat_shorten_esc(gap, exp_str);
224 if (atype != ASSERT_NOTEQUAL)
225 {
226 if (atype == ASSERT_MATCH)
227 ga_concat(gap, (char_u *)" does not match ");
228 else if (atype == ASSERT_NOTMATCH)
229 ga_concat(gap, (char_u *)" does match ");
230 else
231 ga_concat(gap, (char_u *)" but got ");
232 ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
233 vim_free(tofree);
Bram Moolenaar4a021df2020-06-13 15:13:38 +0200234
235 if (omitted != 0)
236 {
237 char buf[100];
238
239 vim_snprintf(buf, 100, " - %d equal item%s omitted",
240 omitted, omitted == 1 ? "" : "s");
241 ga_concat(gap, (char_u *)buf);
242 }
243 }
244
245 if (did_copy)
246 {
247 clear_tv(exp_tv);
248 clear_tv(got_tv);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200249 }
250}
251
252 static int
253assert_equal_common(typval_T *argvars, assert_type_T atype)
254{
255 garray_T ga;
256
257 if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE)
258 != (atype == ASSERT_EQUAL))
259 {
260 prepare_assert_error(&ga);
261 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
262 atype);
263 assert_error(&ga);
264 ga_clear(&ga);
265 return 1;
266 }
267 return 0;
268}
269
270 static int
271assert_match_common(typval_T *argvars, assert_type_T atype)
272{
273 garray_T ga;
274 char_u buf1[NUMBUFLEN];
275 char_u buf2[NUMBUFLEN];
Bram Moolenaar7177da92020-07-12 23:09:20 +0200276 int called_emsg_before = called_emsg;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200277 char_u *pat = tv_get_string_buf_chk(&argvars[0], buf1);
278 char_u *text = tv_get_string_buf_chk(&argvars[1], buf2);
279
Bram Moolenaar7177da92020-07-12 23:09:20 +0200280 if (called_emsg == called_emsg_before
281 && pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH))
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200282 {
283 prepare_assert_error(&ga);
284 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
285 atype);
286 assert_error(&ga);
287 ga_clear(&ga);
288 return 1;
289 }
290 return 0;
291}
292
293/*
294 * Common for assert_true() and assert_false().
295 * Return non-zero for failure.
296 */
297 static int
298assert_bool(typval_T *argvars, int isTrue)
299{
300 int error = FALSE;
301 garray_T ga;
302
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100303 if (argvars[0].v_type == VAR_BOOL
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200304 && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE))
305 return 0;
306 if (argvars[0].v_type != VAR_NUMBER
307 || (tv_get_number_chk(&argvars[0], &error) == 0) == isTrue
308 || error)
309 {
310 prepare_assert_error(&ga);
311 fill_assert_error(&ga, &argvars[1],
312 (char_u *)(isTrue ? "True" : "False"),
313 NULL, &argvars[0], ASSERT_OTHER);
314 assert_error(&ga);
315 ga_clear(&ga);
316 return 1;
317 }
318 return 0;
319}
320
321 static void
322assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, char_u *cmd)
323{
324 char_u *tofree;
325 char_u numbuf[NUMBUFLEN];
326
327 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
328 {
329 ga_concat(gap, echo_string(&argvars[2], &tofree, numbuf, 0));
330 vim_free(tofree);
331 }
332 else
333 ga_concat(gap, cmd);
334}
335
336 static int
337assert_beeps(typval_T *argvars)
338{
339 char_u *cmd = tv_get_string_chk(&argvars[0]);
340 garray_T ga;
341 int ret = 0;
342
343 called_vim_beep = FALSE;
344 suppress_errthrow = TRUE;
345 emsg_silent = FALSE;
346 do_cmdline_cmd(cmd);
347 if (!called_vim_beep)
348 {
349 prepare_assert_error(&ga);
350 ga_concat(&ga, (char_u *)"command did not beep: ");
351 ga_concat(&ga, cmd);
352 assert_error(&ga);
353 ga_clear(&ga);
354 ret = 1;
355 }
356
357 suppress_errthrow = FALSE;
358 emsg_on_display = FALSE;
359 return ret;
360}
361
362/*
363 * "assert_beeps(cmd [, error])" function
364 */
365 void
366f_assert_beeps(typval_T *argvars, typval_T *rettv)
367{
368 rettv->vval.v_number = assert_beeps(argvars);
369}
370
371/*
372 * "assert_equal(expected, actual[, msg])" function
373 */
374 void
375f_assert_equal(typval_T *argvars, typval_T *rettv)
376{
377 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
378}
379
380 static int
381assert_equalfile(typval_T *argvars)
382{
383 char_u buf1[NUMBUFLEN];
384 char_u buf2[NUMBUFLEN];
Bram Moolenaar7177da92020-07-12 23:09:20 +0200385 int called_emsg_before = called_emsg;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200386 char_u *fname1 = tv_get_string_buf_chk(&argvars[0], buf1);
387 char_u *fname2 = tv_get_string_buf_chk(&argvars[1], buf2);
388 garray_T ga;
389 FILE *fd1;
390 FILE *fd2;
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200391 char line1[200];
392 char line2[200];
393 int lineidx = 0;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200394
Bram Moolenaar7177da92020-07-12 23:09:20 +0200395 if (called_emsg > called_emsg_before)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200396 return 0;
397
398 IObuff[0] = NUL;
399 fd1 = mch_fopen((char *)fname1, READBIN);
400 if (fd1 == NULL)
401 {
402 vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname1);
403 }
404 else
405 {
406 fd2 = mch_fopen((char *)fname2, READBIN);
407 if (fd2 == NULL)
408 {
409 fclose(fd1);
410 vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
411 }
412 else
413 {
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200414 int c1, c2;
415 long count = 0;
416 long linecount = 1;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200417
418 for (;;)
419 {
420 c1 = fgetc(fd1);
421 c2 = fgetc(fd2);
422 if (c1 == EOF)
423 {
424 if (c2 != EOF)
425 STRCPY(IObuff, "first file is shorter");
426 break;
427 }
428 else if (c2 == EOF)
429 {
430 STRCPY(IObuff, "second file is shorter");
431 break;
432 }
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200433 else
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200434 {
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200435 line1[lineidx] = c1;
436 line2[lineidx] = c2;
437 ++lineidx;
438 if (c1 != c2)
439 {
440 vim_snprintf((char *)IObuff, IOSIZE,
441 "difference at byte %ld, line %ld",
442 count, linecount);
443 break;
444 }
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200445 }
446 ++count;
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200447 if (c1 == NL)
448 {
449 ++linecount;
450 lineidx = 0;
451 }
452 else if (lineidx + 2 == (int)sizeof(line1))
453 {
454 mch_memmove(line1, line1 + 100, lineidx - 100);
455 mch_memmove(line2, line2 + 100, lineidx - 100);
456 lineidx -= 100;
457 }
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200458 }
459 fclose(fd1);
460 fclose(fd2);
461 }
462 }
463 if (IObuff[0] != NUL)
464 {
465 prepare_assert_error(&ga);
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200466 if (argvars[2].v_type != VAR_UNKNOWN)
467 {
468 char_u numbuf[NUMBUFLEN];
469 char_u *tofree;
470
471 ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0));
472 vim_free(tofree);
473 ga_concat(&ga, (char_u *)": ");
474 }
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200475 ga_concat(&ga, IObuff);
Bram Moolenaar30cc44a2020-06-04 16:52:40 +0200476 if (lineidx > 0)
477 {
478 line1[lineidx] = NUL;
479 line2[lineidx] = NUL;
480 ga_concat(&ga, (char_u *)" after \"");
481 ga_concat(&ga, (char_u *)line1);
482 if (STRCMP(line1, line2) != 0)
483 {
484 ga_concat(&ga, (char_u *)"\" vs \"");
485 ga_concat(&ga, (char_u *)line2);
486 }
487 ga_concat(&ga, (char_u *)"\"");
488 }
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200489 assert_error(&ga);
490 ga_clear(&ga);
491 return 1;
492 }
493 return 0;
494}
495
496/*
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200497 * "assert_equalfile(fname-one, fname-two[, msg])" function
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200498 */
499 void
500f_assert_equalfile(typval_T *argvars, typval_T *rettv)
501{
502 rettv->vval.v_number = assert_equalfile(argvars);
503}
504
505/*
506 * "assert_notequal(expected, actual[, msg])" function
507 */
508 void
509f_assert_notequal(typval_T *argvars, typval_T *rettv)
510{
511 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
512}
513
514/*
515 * "assert_exception(string[, msg])" function
516 */
517 void
518f_assert_exception(typval_T *argvars, typval_T *rettv)
519{
520 garray_T ga;
521 char_u *error = tv_get_string_chk(&argvars[0]);
522
523 if (*get_vim_var_str(VV_EXCEPTION) == NUL)
524 {
525 prepare_assert_error(&ga);
526 ga_concat(&ga, (char_u *)"v:exception is not set");
527 assert_error(&ga);
528 ga_clear(&ga);
529 rettv->vval.v_number = 1;
530 }
531 else if (error != NULL
532 && strstr((char *)get_vim_var_str(VV_EXCEPTION), (char *)error) == NULL)
533 {
534 prepare_assert_error(&ga);
535 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
536 get_vim_var_tv(VV_EXCEPTION), ASSERT_OTHER);
537 assert_error(&ga);
538 ga_clear(&ga);
539 rettv->vval.v_number = 1;
540 }
541}
542
543/*
544 * "assert_fails(cmd [, error[, msg]])" function
545 */
546 void
547f_assert_fails(typval_T *argvars, typval_T *rettv)
548{
549 char_u *cmd = tv_get_string_chk(&argvars[0]);
550 garray_T ga;
551 int save_trylevel = trylevel;
Bram Moolenaar53989552019-12-23 22:59:18 +0100552 int called_emsg_before = called_emsg;
Bram Moolenaar44d66522020-09-06 22:26:57 +0200553 char *wrong_arg_msg = NULL;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200554
555 // trylevel must be zero for a ":throw" command to be considered failed
556 trylevel = 0;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200557 suppress_errthrow = TRUE;
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100558 in_assert_fails = TRUE;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200559
560 do_cmdline_cmd(cmd);
Bram Moolenaar53989552019-12-23 22:59:18 +0100561 if (called_emsg == called_emsg_before)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200562 {
563 prepare_assert_error(&ga);
564 ga_concat(&ga, (char_u *)"command did not fail: ");
565 assert_append_cmd_or_arg(&ga, argvars, cmd);
566 assert_error(&ga);
567 ga_clear(&ga);
568 rettv->vval.v_number = 1;
569 }
570 else if (argvars[1].v_type != VAR_UNKNOWN)
571 {
572 char_u buf[NUMBUFLEN];
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200573 char_u *expected;
574 int error_found = FALSE;
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200575 int error_found_index = 1;
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200576 char_u *actual = emsg_assert_fails_msg == NULL ? (char_u *)"[unknown]"
577 : emsg_assert_fails_msg;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200578
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200579 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200580 {
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200581 expected = tv_get_string_buf_chk(&argvars[1], buf);
582 error_found = expected == NULL
583 || strstr((char *)actual, (char *)expected) == NULL;
584 }
585 else if (argvars[1].v_type == VAR_LIST)
586 {
587 list_T *list = argvars[1].vval.v_list;
588 typval_T *tv;
589
590 if (list == NULL || list->lv_len < 1 || list->lv_len > 2)
591 {
Bram Moolenaar44d66522020-09-06 22:26:57 +0200592 wrong_arg_msg = e_assert_fails_second_arg;
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200593 goto theend;
594 }
595 CHECK_LIST_MATERIALIZE(list);
596 tv = &list->lv_first->li_tv;
597 expected = tv_get_string_buf_chk(tv, buf);
598 if (!pattern_match(expected, actual, FALSE))
599 {
600 error_found = TRUE;
601 }
602 else if (list->lv_len == 2)
603 {
604 tv = &list->lv_u.mat.lv_last->li_tv;
605 actual = get_vim_var_str(VV_ERRMSG);
606 expected = tv_get_string_buf_chk(tv, buf);
607 if (!pattern_match(expected, actual, FALSE))
608 error_found = TRUE;
609 }
610 }
611 else
612 {
Bram Moolenaar44d66522020-09-06 22:26:57 +0200613 wrong_arg_msg = e_assert_fails_second_arg;
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200614 goto theend;
615 }
616
Bram Moolenaar9b02d642020-08-18 23:24:13 +0200617 if (!error_found && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaar44d66522020-09-06 22:26:57 +0200618 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaar1d634542020-08-18 13:41:50 +0200619 {
Bram Moolenaar44d66522020-09-06 22:26:57 +0200620 if (argvars[3].v_type != VAR_NUMBER)
621 {
622 wrong_arg_msg = e_assert_fails_fourth_argument;
623 goto theend;
624 }
625 else if (argvars[3].vval.v_number >= 0
626 && argvars[3].vval.v_number != emsg_assert_fails_lnum)
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200627 {
628 error_found = TRUE;
629 error_found_index = 3;
630 }
Bram Moolenaar44d66522020-09-06 22:26:57 +0200631 if (!error_found && argvars[4].v_type != VAR_UNKNOWN)
632 {
633 if (argvars[4].v_type != VAR_STRING)
634 {
635 wrong_arg_msg = e_assert_fails_fifth_argument;
636 goto theend;
637 }
638 else if (argvars[4].vval.v_string != NULL
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200639 && !pattern_match(argvars[4].vval.v_string,
640 emsg_assert_fails_context, FALSE))
Bram Moolenaar44d66522020-09-06 22:26:57 +0200641 {
642 error_found = TRUE;
643 error_found_index = 4;
644 }
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200645 }
Bram Moolenaar1d634542020-08-18 13:41:50 +0200646 }
647
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200648 if (error_found)
649 {
650 typval_T actual_tv;
651
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200652 prepare_assert_error(&ga);
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200653 if (error_found_index == 3)
Bram Moolenaar1d634542020-08-18 13:41:50 +0200654 {
655 actual_tv.v_type = VAR_NUMBER;
656 actual_tv.vval.v_number = emsg_assert_fails_lnum;
657 }
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200658 else if (error_found_index == 4)
659 {
660 actual_tv.v_type = VAR_STRING;
661 actual_tv.vval.v_string = emsg_assert_fails_context;
662 }
Bram Moolenaar1d634542020-08-18 13:41:50 +0200663 else
664 {
665 actual_tv.v_type = VAR_STRING;
666 actual_tv.vval.v_string = actual;
667 }
668 fill_assert_error(&ga, &argvars[2], NULL,
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200669 &argvars[error_found_index], &actual_tv, ASSERT_OTHER);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200670 ga_concat(&ga, (char_u *)": ");
671 assert_append_cmd_or_arg(&ga, argvars, cmd);
672 assert_error(&ga);
673 ga_clear(&ga);
674 rettv->vval.v_number = 1;
675 }
676 }
677
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200678theend:
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200679 trylevel = save_trylevel;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200680 suppress_errthrow = FALSE;
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100681 in_assert_fails = FALSE;
682 did_emsg = FALSE;
683 msg_col = 0;
684 need_wait_return = FALSE;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200685 emsg_on_display = FALSE;
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100686 msg_scrolled = 0;
687 lines_left = Rows;
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200688 VIM_CLEAR(emsg_assert_fails_msg);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200689 set_vim_var_string(VV_ERRMSG, NULL, 0);
Bram Moolenaar44d66522020-09-06 22:26:57 +0200690 if (wrong_arg_msg != NULL)
691 emsg(_(wrong_arg_msg));
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200692}
693
694/*
695 * "assert_false(actual[, msg])" function
696 */
697 void
698f_assert_false(typval_T *argvars, typval_T *rettv)
699{
700 rettv->vval.v_number = assert_bool(argvars, FALSE);
701}
702
703 static int
704assert_inrange(typval_T *argvars)
705{
706 garray_T ga;
707 int error = FALSE;
708 char_u *tofree;
709 char msg[200];
710 char_u numbuf[NUMBUFLEN];
711
712#ifdef FEAT_FLOAT
713 if (argvars[0].v_type == VAR_FLOAT
714 || argvars[1].v_type == VAR_FLOAT
715 || argvars[2].v_type == VAR_FLOAT)
716 {
717 float_T flower = tv_get_float(&argvars[0]);
718 float_T fupper = tv_get_float(&argvars[1]);
719 float_T factual = tv_get_float(&argvars[2]);
720
721 if (factual < flower || factual > fupper)
722 {
723 prepare_assert_error(&ga);
724 if (argvars[3].v_type != VAR_UNKNOWN)
725 {
726 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
727 vim_free(tofree);
728 }
729 else
730 {
731 vim_snprintf(msg, 200, "Expected range %g - %g, but got %g",
732 flower, fupper, factual);
733 ga_concat(&ga, (char_u *)msg);
734 }
735 assert_error(&ga);
736 ga_clear(&ga);
737 return 1;
738 }
739 }
740 else
741#endif
742 {
743 varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
744 varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
745 varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
746
747 if (error)
748 return 0;
749 if (actual < lower || actual > upper)
750 {
751 prepare_assert_error(&ga);
752 if (argvars[3].v_type != VAR_UNKNOWN)
753 {
754 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
755 vim_free(tofree);
756 }
757 else
758 {
759 vim_snprintf(msg, 200, "Expected range %ld - %ld, but got %ld",
760 (long)lower, (long)upper, (long)actual);
761 ga_concat(&ga, (char_u *)msg);
762 }
763 assert_error(&ga);
764 ga_clear(&ga);
765 return 1;
766 }
767 }
768 return 0;
769}
770
771/*
772 * "assert_inrange(lower, upper[, msg])" function
773 */
774 void
775f_assert_inrange(typval_T *argvars, typval_T *rettv)
776{
777 rettv->vval.v_number = assert_inrange(argvars);
778}
779
780/*
781 * "assert_match(pattern, actual[, msg])" function
782 */
783 void
784f_assert_match(typval_T *argvars, typval_T *rettv)
785{
786 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
787}
788
789/*
790 * "assert_notmatch(pattern, actual[, msg])" function
791 */
792 void
793f_assert_notmatch(typval_T *argvars, typval_T *rettv)
794{
795 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
796}
797
798/*
799 * "assert_report(msg)" function
800 */
801 void
802f_assert_report(typval_T *argvars, typval_T *rettv)
803{
804 garray_T ga;
805
806 prepare_assert_error(&ga);
807 ga_concat(&ga, tv_get_string(&argvars[0]));
808 assert_error(&ga);
809 ga_clear(&ga);
810 rettv->vval.v_number = 1;
811}
812
813/*
814 * "assert_true(actual[, msg])" function
815 */
816 void
817f_assert_true(typval_T *argvars, typval_T *rettv)
818{
819 rettv->vval.v_number = assert_bool(argvars, TRUE);
820}
821
822/*
823 * "test_alloc_fail(id, countdown, repeat)" function
824 */
825 void
826f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
827{
828 if (argvars[0].v_type != VAR_NUMBER
829 || argvars[0].vval.v_number <= 0
830 || argvars[1].v_type != VAR_NUMBER
831 || argvars[1].vval.v_number < 0
832 || argvars[2].v_type != VAR_NUMBER)
833 emsg(_(e_invarg));
834 else
835 {
836 alloc_fail_id = argvars[0].vval.v_number;
837 if (alloc_fail_id >= aid_last)
838 emsg(_(e_invarg));
839 alloc_fail_countdown = argvars[1].vval.v_number;
840 alloc_fail_repeat = argvars[2].vval.v_number;
841 did_outofmem_msg = FALSE;
842 }
843}
844
845/*
846 * "test_autochdir()"
847 */
848 void
849f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
850{
851#if defined(FEAT_AUTOCHDIR)
852 test_autochdir = TRUE;
853#endif
854}
855
856/*
857 * "test_feedinput()"
858 */
859 void
860f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
861{
862#ifdef USE_INPUT_BUF
863 char_u *val = tv_get_string_chk(&argvars[0]);
864
Bram Moolenaar272ca952020-01-28 20:49:11 +0100865# ifdef VIMDLL
866 // this doesn't work in the console
867 if (!gui.in_use)
868 return;
869# endif
870
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200871 if (val != NULL)
872 {
873 trash_input_buf();
874 add_to_input_buf_csi(val, (int)STRLEN(val));
875 }
876#endif
877}
878
879/*
880 * "test_getvalue({name})" function
881 */
882 void
883f_test_getvalue(typval_T *argvars, typval_T *rettv)
884{
885 if (argvars[0].v_type != VAR_STRING)
886 emsg(_(e_invarg));
887 else
888 {
889 char_u *name = tv_get_string(&argvars[0]);
890
891 if (STRCMP(name, (char_u *)"need_fileinfo") == 0)
892 rettv->vval.v_number = need_fileinfo;
893 else
894 semsg(_(e_invarg2), name);
895 }
896}
897
898/*
899 * "test_option_not_set({name})" function
900 */
901 void
902f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
903{
904 char_u *name = (char_u *)"";
905
906 if (argvars[0].v_type != VAR_STRING)
907 emsg(_(e_invarg));
908 else
909 {
910 name = tv_get_string(&argvars[0]);
911 if (reset_option_was_set(name) == FAIL)
912 semsg(_(e_invarg2), name);
913 }
914}
915
916/*
917 * "test_override({name}, {val})" function
918 */
919 void
920f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
921{
922 char_u *name = (char_u *)"";
923 int val;
924 static int save_starting = -1;
925
926 if (argvars[0].v_type != VAR_STRING
927 || (argvars[1].v_type) != VAR_NUMBER)
928 emsg(_(e_invarg));
929 else
930 {
931 name = tv_get_string(&argvars[0]);
932 val = (int)tv_get_number(&argvars[1]);
933
934 if (STRCMP(name, (char_u *)"redraw") == 0)
935 disable_redraw_for_testing = val;
936 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
937 ignore_redraw_flag_for_testing = val;
938 else if (STRCMP(name, (char_u *)"char_avail") == 0)
939 disable_char_avail_for_testing = val;
940 else if (STRCMP(name, (char_u *)"starting") == 0)
941 {
942 if (val)
943 {
944 if (save_starting < 0)
945 save_starting = starting;
946 starting = 0;
947 }
948 else
949 {
950 starting = save_starting;
951 save_starting = -1;
952 }
953 }
954 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
955 nfa_fail_for_testing = val;
956 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
957 no_query_mouse_for_testing = val;
958 else if (STRCMP(name, (char_u *)"no_wait_return") == 0)
959 no_wait_return = val;
Bram Moolenaarb340bae2020-06-15 19:51:56 +0200960 else if (STRCMP(name, (char_u *)"ui_delay") == 0)
961 ui_delay_for_testing = val;
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +0200962 else if (STRCMP(name, (char_u *)"term_props") == 0)
963 reset_term_props_on_termresponse = val;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200964 else if (STRCMP(name, (char_u *)"ALL") == 0)
965 {
966 disable_char_avail_for_testing = FALSE;
967 disable_redraw_for_testing = FALSE;
968 ignore_redraw_flag_for_testing = FALSE;
969 nfa_fail_for_testing = FALSE;
970 no_query_mouse_for_testing = FALSE;
Bram Moolenaarb340bae2020-06-15 19:51:56 +0200971 ui_delay_for_testing = 0;
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +0200972 reset_term_props_on_termresponse = FALSE;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200973 if (save_starting >= 0)
974 {
975 starting = save_starting;
976 save_starting = -1;
977 }
978 }
979 else
980 semsg(_(e_invarg2), name);
981 }
982}
983
984/*
985 * "test_refcount({expr})" function
986 */
987 void
988f_test_refcount(typval_T *argvars, typval_T *rettv)
989{
990 int retval = -1;
991
992 switch (argvars[0].v_type)
993 {
994 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +0200995 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100996 case VAR_VOID:
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200997 case VAR_NUMBER:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100998 case VAR_BOOL:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100999 case VAR_FLOAT:
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001000 case VAR_SPECIAL:
1001 case VAR_STRING:
1002 break;
1003 case VAR_JOB:
1004#ifdef FEAT_JOB_CHANNEL
1005 if (argvars[0].vval.v_job != NULL)
1006 retval = argvars[0].vval.v_job->jv_refcount - 1;
1007#endif
1008 break;
1009 case VAR_CHANNEL:
1010#ifdef FEAT_JOB_CHANNEL
1011 if (argvars[0].vval.v_channel != NULL)
1012 retval = argvars[0].vval.v_channel->ch_refcount - 1;
1013#endif
1014 break;
1015 case VAR_FUNC:
1016 if (argvars[0].vval.v_string != NULL)
1017 {
1018 ufunc_T *fp;
1019
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02001020 fp = find_func(argvars[0].vval.v_string, FALSE, NULL);
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001021 if (fp != NULL)
1022 retval = fp->uf_refcount;
1023 }
1024 break;
1025 case VAR_PARTIAL:
1026 if (argvars[0].vval.v_partial != NULL)
1027 retval = argvars[0].vval.v_partial->pt_refcount - 1;
1028 break;
1029 case VAR_BLOB:
1030 if (argvars[0].vval.v_blob != NULL)
1031 retval = argvars[0].vval.v_blob->bv_refcount - 1;
1032 break;
1033 case VAR_LIST:
1034 if (argvars[0].vval.v_list != NULL)
1035 retval = argvars[0].vval.v_list->lv_refcount - 1;
1036 break;
1037 case VAR_DICT:
1038 if (argvars[0].vval.v_dict != NULL)
1039 retval = argvars[0].vval.v_dict->dv_refcount - 1;
1040 break;
1041 }
1042
1043 rettv->v_type = VAR_NUMBER;
1044 rettv->vval.v_number = retval;
1045
1046}
1047
1048/*
1049 * "test_garbagecollect_now()" function
1050 */
1051 void
1052f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1053{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +01001054 // This is dangerous, any Lists and Dicts used internally may be freed
1055 // while still in use.
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001056 garbage_collect(TRUE);
1057}
1058
1059/*
1060 * "test_garbagecollect_soon()" function
1061 */
1062 void
1063f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1064{
1065 may_garbage_collect = TRUE;
1066}
1067
1068/*
1069 * "test_ignore_error()" function
1070 */
1071 void
1072f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
1073{
1074 ignore_error_for_testing(tv_get_string(&argvars[0]));
1075}
1076
1077 void
1078f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
1079{
1080 rettv->v_type = VAR_BLOB;
1081 rettv->vval.v_blob = NULL;
1082}
1083
1084#ifdef FEAT_JOB_CHANNEL
1085 void
1086f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
1087{
1088 rettv->v_type = VAR_CHANNEL;
1089 rettv->vval.v_channel = NULL;
1090}
1091#endif
1092
1093 void
1094f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
1095{
1096 rettv_dict_set(rettv, NULL);
1097}
1098
1099#ifdef FEAT_JOB_CHANNEL
1100 void
1101f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
1102{
1103 rettv->v_type = VAR_JOB;
1104 rettv->vval.v_job = NULL;
1105}
1106#endif
1107
1108 void
1109f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
1110{
1111 rettv_list_set(rettv, NULL);
1112}
1113
1114 void
Bram Moolenaare69f6d02020-04-01 22:11:01 +02001115f_test_null_function(typval_T *argvars UNUSED, typval_T *rettv)
1116{
1117 rettv->v_type = VAR_FUNC;
1118 rettv->vval.v_string = NULL;
1119}
1120
1121 void
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001122f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
1123{
1124 rettv->v_type = VAR_PARTIAL;
1125 rettv->vval.v_partial = NULL;
1126}
1127
1128 void
1129f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
1130{
1131 rettv->v_type = VAR_STRING;
1132 rettv->vval.v_string = NULL;
1133}
1134
Bram Moolenaar8ed04582020-02-22 19:07:28 +01001135 void
1136f_test_unknown(typval_T *argvars UNUSED, typval_T *rettv)
1137{
1138 rettv->v_type = VAR_UNKNOWN;
1139}
1140
1141 void
1142f_test_void(typval_T *argvars UNUSED, typval_T *rettv)
1143{
1144 rettv->v_type = VAR_VOID;
1145}
1146
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001147#ifdef FEAT_GUI
1148 void
1149f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
1150{
1151 char_u *which;
1152 long value;
1153 int dragging;
1154 scrollbar_T *sb = NULL;
1155
1156 if (argvars[0].v_type != VAR_STRING
1157 || (argvars[1].v_type) != VAR_NUMBER
1158 || (argvars[2].v_type) != VAR_NUMBER)
1159 {
1160 emsg(_(e_invarg));
1161 return;
1162 }
1163 which = tv_get_string(&argvars[0]);
1164 value = tv_get_number(&argvars[1]);
1165 dragging = tv_get_number(&argvars[2]);
1166
1167 if (STRCMP(which, "left") == 0)
1168 sb = &curwin->w_scrollbars[SBAR_LEFT];
1169 else if (STRCMP(which, "right") == 0)
1170 sb = &curwin->w_scrollbars[SBAR_RIGHT];
1171 else if (STRCMP(which, "hor") == 0)
1172 sb = &gui.bottom_sbar;
1173 if (sb == NULL)
1174 {
1175 semsg(_(e_invarg2), which);
1176 return;
1177 }
1178 gui_drag_scrollbar(sb, value, dragging);
1179# ifndef USE_ON_FLY_SCROLL
1180 // need to loop through normal_cmd() to handle the scroll events
1181 exec_normal(FALSE, TRUE, FALSE);
1182# endif
1183}
1184#endif
1185
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001186 void
1187f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
1188{
1189 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
1190 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
1191}
Bram Moolenaarecaa70e2019-07-14 14:55:39 +02001192
1193 void
1194f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
1195{
1196 time_for_testing = (time_t)tv_get_number(&argvars[0]);
1197}
1198
1199
1200#endif // defined(FEAT_EVAL)