xref: /vim-8.2.3635/src/testing.c (revision 125ed274)
1 /* 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
22 prepare_assert_error(garray_T *gap)
23 {
24     char    buf[NUMBUFLEN];
25     char_u  *sname = estack_sfile(ESTACK_NONE);
26 
27     ga_init2(gap, 1, 100);
28     if (sname != NULL)
29     {
30 	ga_concat(gap, sname);
31 	if (SOURCING_LNUM > 0)
32 	    ga_concat(gap, (char_u *)" ");
33     }
34     if (SOURCING_LNUM > 0)
35     {
36 	sprintf(buf, "line %ld", (long)SOURCING_LNUM);
37 	ga_concat(gap, (char_u *)buf);
38     }
39     if (sname != NULL || SOURCING_LNUM > 0)
40 	ga_concat(gap, (char_u *)": ");
41     vim_free(sname);
42 }
43 
44 /*
45  * Append "p[clen]" to "gap", escaping unprintable characters.
46  * Changes NL to \n, CR to \r, etc.
47  */
48     static void
49 ga_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:
69 		   if (*p < ' ' || *p == 0x7f)
70 		   {
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
85 ga_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
130 fill_assert_error(
131     garray_T	*gap,
132     typval_T	*opt_msg_tv,
133     char_u      *exp_str,
134     typval_T	*exp_tv_arg,
135     typval_T	*got_tv_arg,
136     assert_type_T atype)
137 {
138     char_u	numbuf[NUMBUFLEN];
139     char_u	*tofree;
140     typval_T	*exp_tv = exp_tv_arg;
141     typval_T	*got_tv = got_tv_arg;
142     int		did_copy = FALSE;
143     int		omitted = 0;
144 
145     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)))
149     {
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     {
163 	// 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 
219 	ga_concat_shorten_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
220 	vim_free(tofree);
221     }
222     else
223     {
224 	ga_concat(gap, (char_u *)"'");
225 	ga_concat_shorten_esc(gap, exp_str);
226 	ga_concat(gap, (char_u *)"'");
227     }
228     if (atype != ASSERT_NOTEQUAL)
229     {
230 	if (atype == ASSERT_MATCH)
231 	    ga_concat(gap, (char_u *)" does not match ");
232 	else if (atype == ASSERT_NOTMATCH)
233 	    ga_concat(gap, (char_u *)" does match ");
234 	else
235 	    ga_concat(gap, (char_u *)" but got ");
236 	ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
237 	vim_free(tofree);
238 
239 	if (omitted != 0)
240 	{
241 	    char buf[100];
242 
243 	    vim_snprintf(buf, 100, " - %d equal item%s omitted",
244 					     omitted, omitted == 1 ? "" : "s");
245 	    ga_concat(gap, (char_u *)buf);
246 	}
247     }
248 
249     if (did_copy)
250     {
251 	clear_tv(exp_tv);
252 	clear_tv(got_tv);
253     }
254 }
255 
256     static int
257 assert_equal_common(typval_T *argvars, assert_type_T atype)
258 {
259     garray_T	ga;
260 
261     if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE)
262 						   != (atype == ASSERT_EQUAL))
263     {
264 	prepare_assert_error(&ga);
265 	fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
266 								       atype);
267 	assert_error(&ga);
268 	ga_clear(&ga);
269 	return 1;
270     }
271     return 0;
272 }
273 
274     static int
275 assert_match_common(typval_T *argvars, assert_type_T atype)
276 {
277     garray_T	ga;
278     char_u	buf1[NUMBUFLEN];
279     char_u	buf2[NUMBUFLEN];
280     int		called_emsg_before = called_emsg;
281     char_u	*pat = tv_get_string_buf_chk(&argvars[0], buf1);
282     char_u	*text = tv_get_string_buf_chk(&argvars[1], buf2);
283 
284     if (called_emsg == called_emsg_before
285 		 && pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH))
286     {
287 	prepare_assert_error(&ga);
288 	fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
289 									atype);
290 	assert_error(&ga);
291 	ga_clear(&ga);
292 	return 1;
293     }
294     return 0;
295 }
296 
297 /*
298  * Common for assert_true() and assert_false().
299  * Return non-zero for failure.
300  */
301     static int
302 assert_bool(typval_T *argvars, int isTrue)
303 {
304     int		error = FALSE;
305     garray_T	ga;
306 
307     if (argvars[0].v_type == VAR_BOOL
308 	    && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE))
309 	return 0;
310     if (argvars[0].v_type != VAR_NUMBER
311 	    || (tv_get_number_chk(&argvars[0], &error) == 0) == isTrue
312 	    || error)
313     {
314 	prepare_assert_error(&ga);
315 	fill_assert_error(&ga, &argvars[1],
316 		(char_u *)(isTrue ? "True" : "False"),
317 		NULL, &argvars[0], ASSERT_OTHER);
318 	assert_error(&ga);
319 	ga_clear(&ga);
320 	return 1;
321     }
322     return 0;
323 }
324 
325     static void
326 assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, char_u *cmd)
327 {
328     char_u	*tofree;
329     char_u	numbuf[NUMBUFLEN];
330 
331     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
332     {
333 	ga_concat(gap, echo_string(&argvars[2], &tofree, numbuf, 0));
334 	vim_free(tofree);
335     }
336     else
337 	ga_concat(gap, cmd);
338 }
339 
340     static int
341 assert_beeps(typval_T *argvars, int no_beep)
342 {
343     char_u	*cmd = tv_get_string_chk(&argvars[0]);
344     garray_T	ga;
345     int		ret = 0;
346 
347     called_vim_beep = FALSE;
348     suppress_errthrow = TRUE;
349     emsg_silent = FALSE;
350     do_cmdline_cmd(cmd);
351     if (no_beep ? called_vim_beep : !called_vim_beep)
352     {
353 	prepare_assert_error(&ga);
354 	if (no_beep)
355 	    ga_concat(&ga, (char_u *)"command did beep: ");
356 	else
357 	    ga_concat(&ga, (char_u *)"command did not beep: ");
358 	ga_concat(&ga, cmd);
359 	assert_error(&ga);
360 	ga_clear(&ga);
361 	ret = 1;
362     }
363 
364     suppress_errthrow = FALSE;
365     emsg_on_display = FALSE;
366     return ret;
367 }
368 
369 /*
370  * "assert_beeps(cmd [, error])" function
371  */
372     void
373 f_assert_beeps(typval_T *argvars, typval_T *rettv)
374 {
375     rettv->vval.v_number = assert_beeps(argvars, FALSE);
376 }
377 
378 /*
379  * "assert_nobeep(cmd [, error])" function
380  */
381     void
382 f_assert_nobeep(typval_T *argvars, typval_T *rettv)
383 {
384     rettv->vval.v_number = assert_beeps(argvars, TRUE);
385 }
386 
387 /*
388  * "assert_equal(expected, actual[, msg])" function
389  */
390     void
391 f_assert_equal(typval_T *argvars, typval_T *rettv)
392 {
393     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
394 }
395 
396     static int
397 assert_equalfile(typval_T *argvars)
398 {
399     char_u	buf1[NUMBUFLEN];
400     char_u	buf2[NUMBUFLEN];
401     int		called_emsg_before = called_emsg;
402     char_u	*fname1 = tv_get_string_buf_chk(&argvars[0], buf1);
403     char_u	*fname2 = tv_get_string_buf_chk(&argvars[1], buf2);
404     garray_T	ga;
405     FILE	*fd1;
406     FILE	*fd2;
407     char	line1[200];
408     char	line2[200];
409     int		lineidx = 0;
410 
411     if (called_emsg > called_emsg_before)
412 	return 0;
413 
414     IObuff[0] = NUL;
415     fd1 = mch_fopen((char *)fname1, READBIN);
416     if (fd1 == NULL)
417     {
418 	vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname1);
419     }
420     else
421     {
422 	fd2 = mch_fopen((char *)fname2, READBIN);
423 	if (fd2 == NULL)
424 	{
425 	    fclose(fd1);
426 	    vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
427 	}
428 	else
429 	{
430 	    int	    c1, c2;
431 	    long    count = 0;
432 	    long    linecount = 1;
433 
434 	    for (;;)
435 	    {
436 		c1 = fgetc(fd1);
437 		c2 = fgetc(fd2);
438 		if (c1 == EOF)
439 		{
440 		    if (c2 != EOF)
441 			STRCPY(IObuff, "first file is shorter");
442 		    break;
443 		}
444 		else if (c2 == EOF)
445 		{
446 		    STRCPY(IObuff, "second file is shorter");
447 		    break;
448 		}
449 		else
450 		{
451 		    line1[lineidx] = c1;
452 		    line2[lineidx] = c2;
453 		    ++lineidx;
454 		    if (c1 != c2)
455 		    {
456 			vim_snprintf((char *)IObuff, IOSIZE,
457 					    "difference at byte %ld, line %ld",
458 							     count, linecount);
459 			break;
460 		    }
461 		}
462 		++count;
463 		if (c1 == NL)
464 		{
465 		    ++linecount;
466 		    lineidx = 0;
467 		}
468 		else if (lineidx + 2 == (int)sizeof(line1))
469 		{
470 		    mch_memmove(line1, line1 + 100, lineidx - 100);
471 		    mch_memmove(line2, line2 + 100, lineidx - 100);
472 		    lineidx -= 100;
473 		}
474 	    }
475 	    fclose(fd1);
476 	    fclose(fd2);
477 	}
478     }
479     if (IObuff[0] != NUL)
480     {
481 	prepare_assert_error(&ga);
482 	if (argvars[2].v_type != VAR_UNKNOWN)
483 	{
484 	    char_u	numbuf[NUMBUFLEN];
485 	    char_u	*tofree;
486 
487 	    ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0));
488 	    vim_free(tofree);
489 	    ga_concat(&ga, (char_u *)": ");
490 	}
491 	ga_concat(&ga, IObuff);
492 	if (lineidx > 0)
493 	{
494 	    line1[lineidx] = NUL;
495 	    line2[lineidx] = NUL;
496 	    ga_concat(&ga, (char_u *)" after \"");
497 	    ga_concat(&ga, (char_u *)line1);
498 	    if (STRCMP(line1, line2) != 0)
499 	    {
500 		ga_concat(&ga, (char_u *)"\" vs \"");
501 		ga_concat(&ga, (char_u *)line2);
502 	    }
503 	    ga_concat(&ga, (char_u *)"\"");
504 	}
505 	assert_error(&ga);
506 	ga_clear(&ga);
507 	return 1;
508     }
509     return 0;
510 }
511 
512 /*
513  * "assert_equalfile(fname-one, fname-two[, msg])" function
514  */
515     void
516 f_assert_equalfile(typval_T *argvars, typval_T *rettv)
517 {
518     rettv->vval.v_number = assert_equalfile(argvars);
519 }
520 
521 /*
522  * "assert_notequal(expected, actual[, msg])" function
523  */
524     void
525 f_assert_notequal(typval_T *argvars, typval_T *rettv)
526 {
527     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
528 }
529 
530 /*
531  * "assert_exception(string[, msg])" function
532  */
533     void
534 f_assert_exception(typval_T *argvars, typval_T *rettv)
535 {
536     garray_T	ga;
537     char_u	*error = tv_get_string_chk(&argvars[0]);
538 
539     if (*get_vim_var_str(VV_EXCEPTION) == NUL)
540     {
541 	prepare_assert_error(&ga);
542 	ga_concat(&ga, (char_u *)"v:exception is not set");
543 	assert_error(&ga);
544 	ga_clear(&ga);
545 	rettv->vval.v_number = 1;
546     }
547     else if (error != NULL
548 	&& strstr((char *)get_vim_var_str(VV_EXCEPTION), (char *)error) == NULL)
549     {
550 	prepare_assert_error(&ga);
551 	fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
552 				  get_vim_var_tv(VV_EXCEPTION), ASSERT_OTHER);
553 	assert_error(&ga);
554 	ga_clear(&ga);
555 	rettv->vval.v_number = 1;
556     }
557 }
558 
559 /*
560  * "assert_fails(cmd [, error[, msg]])" function
561  */
562     void
563 f_assert_fails(typval_T *argvars, typval_T *rettv)
564 {
565     char_u	*cmd = tv_get_string_chk(&argvars[0]);
566     garray_T	ga;
567     int		save_trylevel = trylevel;
568     int		called_emsg_before = called_emsg;
569     char	*wrong_arg_msg = NULL;
570 
571     // trylevel must be zero for a ":throw" command to be considered failed
572     trylevel = 0;
573     suppress_errthrow = TRUE;
574     in_assert_fails = TRUE;
575 
576     do_cmdline_cmd(cmd);
577     if (called_emsg == called_emsg_before)
578     {
579 	prepare_assert_error(&ga);
580 	ga_concat(&ga, (char_u *)"command did not fail: ");
581 	assert_append_cmd_or_arg(&ga, argvars, cmd);
582 	assert_error(&ga);
583 	ga_clear(&ga);
584 	rettv->vval.v_number = 1;
585     }
586     else if (argvars[1].v_type != VAR_UNKNOWN)
587     {
588 	char_u	buf[NUMBUFLEN];
589 	char_u	*expected;
590 	char_u	*expected_str = NULL;
591 	int	error_found = FALSE;
592 	int	error_found_index = 1;
593 	char_u	*actual = emsg_assert_fails_msg == NULL ? (char_u *)"[unknown]"
594 						       : emsg_assert_fails_msg;
595 
596 	if (argvars[1].v_type == VAR_STRING)
597 	{
598 	    expected = tv_get_string_buf_chk(&argvars[1], buf);
599 	    error_found = expected == NULL
600 			   || strstr((char *)actual, (char *)expected) == NULL;
601 	}
602 	else if (argvars[1].v_type == VAR_LIST)
603 	{
604 	    list_T	*list = argvars[1].vval.v_list;
605 	    typval_T	*tv;
606 
607 	    if (list == NULL || list->lv_len < 1 || list->lv_len > 2)
608 	    {
609 		wrong_arg_msg = e_assert_fails_second_arg;
610 		goto theend;
611 	    }
612 	    CHECK_LIST_MATERIALIZE(list);
613 	    tv = &list->lv_first->li_tv;
614 	    expected = tv_get_string_buf_chk(tv, buf);
615 	    if (!pattern_match(expected, actual, FALSE))
616 	    {
617 		error_found = TRUE;
618 		expected_str = expected;
619 	    }
620 	    else if (list->lv_len == 2)
621 	    {
622 		tv = &list->lv_u.mat.lv_last->li_tv;
623 		actual = get_vim_var_str(VV_ERRMSG);
624 		expected = tv_get_string_buf_chk(tv, buf);
625 		if (!pattern_match(expected, actual, FALSE))
626 		{
627 		    error_found = TRUE;
628 		    expected_str = expected;
629 		}
630 	    }
631 	}
632 	else
633 	{
634 	    wrong_arg_msg = e_assert_fails_second_arg;
635 	    goto theend;
636 	}
637 
638 	if (!error_found && argvars[2].v_type != VAR_UNKNOWN
639 		&& argvars[3].v_type != VAR_UNKNOWN)
640 	{
641 	    if (argvars[3].v_type != VAR_NUMBER)
642 	    {
643 		wrong_arg_msg = e_assert_fails_fourth_argument;
644 		goto theend;
645 	    }
646 	    else if (argvars[3].vval.v_number >= 0
647 			 && argvars[3].vval.v_number != emsg_assert_fails_lnum)
648 	    {
649 		error_found = TRUE;
650 		error_found_index = 3;
651 	    }
652 	    if (!error_found && argvars[4].v_type != VAR_UNKNOWN)
653 	    {
654 		if (argvars[4].v_type != VAR_STRING)
655 		{
656 		    wrong_arg_msg = e_assert_fails_fifth_argument;
657 		    goto theend;
658 		}
659 		else if (argvars[4].vval.v_string != NULL
660 		    && !pattern_match(argvars[4].vval.v_string,
661 					     emsg_assert_fails_context, FALSE))
662 		{
663 		    error_found = TRUE;
664 		    error_found_index = 4;
665 		}
666 	    }
667 	}
668 
669 	if (error_found)
670 	{
671 	    typval_T actual_tv;
672 
673 	    prepare_assert_error(&ga);
674 	    if (error_found_index == 3)
675 	    {
676 		actual_tv.v_type = VAR_NUMBER;
677 		actual_tv.vval.v_number = emsg_assert_fails_lnum;
678 	    }
679 	    else if (error_found_index == 4)
680 	    {
681 		actual_tv.v_type = VAR_STRING;
682 		actual_tv.vval.v_string = emsg_assert_fails_context;
683 	    }
684 	    else
685 	    {
686 		actual_tv.v_type = VAR_STRING;
687 		actual_tv.vval.v_string = actual;
688 	    }
689 	    fill_assert_error(&ga, &argvars[2], expected_str,
690 			&argvars[error_found_index], &actual_tv, ASSERT_OTHER);
691 	    ga_concat(&ga, (char_u *)": ");
692 	    assert_append_cmd_or_arg(&ga, argvars, cmd);
693 	    assert_error(&ga);
694 	    ga_clear(&ga);
695 	    rettv->vval.v_number = 1;
696 	}
697     }
698 
699 theend:
700     trylevel = save_trylevel;
701     suppress_errthrow = FALSE;
702     in_assert_fails = FALSE;
703     did_emsg = FALSE;
704     msg_col = 0;
705     need_wait_return = FALSE;
706     emsg_on_display = FALSE;
707     msg_scrolled = 0;
708     lines_left = Rows;
709     VIM_CLEAR(emsg_assert_fails_msg);
710     set_vim_var_string(VV_ERRMSG, NULL, 0);
711     if (wrong_arg_msg != NULL)
712 	emsg(_(wrong_arg_msg));
713 }
714 
715 /*
716  * "assert_false(actual[, msg])" function
717  */
718     void
719 f_assert_false(typval_T *argvars, typval_T *rettv)
720 {
721     rettv->vval.v_number = assert_bool(argvars, FALSE);
722 }
723 
724     static int
725 assert_inrange(typval_T *argvars)
726 {
727     garray_T	ga;
728     int		error = FALSE;
729     char_u	*tofree;
730     char	msg[200];
731     char_u	numbuf[NUMBUFLEN];
732 
733 #ifdef FEAT_FLOAT
734     if (argvars[0].v_type == VAR_FLOAT
735 	    || argvars[1].v_type == VAR_FLOAT
736 	    || argvars[2].v_type == VAR_FLOAT)
737     {
738 	float_T flower = tv_get_float(&argvars[0]);
739 	float_T fupper = tv_get_float(&argvars[1]);
740 	float_T factual = tv_get_float(&argvars[2]);
741 
742 	if (factual < flower || factual > fupper)
743 	{
744 	    prepare_assert_error(&ga);
745 	    if (argvars[3].v_type != VAR_UNKNOWN)
746 	    {
747 		ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
748 		vim_free(tofree);
749 	    }
750 	    else
751 	    {
752 		vim_snprintf(msg, 200, "Expected range %g - %g, but got %g",
753 						      flower, fupper, factual);
754 		ga_concat(&ga, (char_u *)msg);
755 	    }
756 	    assert_error(&ga);
757 	    ga_clear(&ga);
758 	    return 1;
759 	}
760     }
761     else
762 #endif
763     {
764 	varnumber_T	lower = tv_get_number_chk(&argvars[0], &error);
765 	varnumber_T	upper = tv_get_number_chk(&argvars[1], &error);
766 	varnumber_T	actual = tv_get_number_chk(&argvars[2], &error);
767 
768 	if (error)
769 	    return 0;
770 	if (actual < lower || actual > upper)
771 	{
772 	    prepare_assert_error(&ga);
773 	    if (argvars[3].v_type != VAR_UNKNOWN)
774 	    {
775 		ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
776 		vim_free(tofree);
777 	    }
778 	    else
779 	    {
780 		vim_snprintf(msg, 200, "Expected range %ld - %ld, but got %ld",
781 				       (long)lower, (long)upper, (long)actual);
782 		ga_concat(&ga, (char_u *)msg);
783 	    }
784 	    assert_error(&ga);
785 	    ga_clear(&ga);
786 	    return 1;
787 	}
788     }
789     return 0;
790 }
791 
792 /*
793  * "assert_inrange(lower, upper[, msg])" function
794  */
795     void
796 f_assert_inrange(typval_T *argvars, typval_T *rettv)
797 {
798     rettv->vval.v_number = assert_inrange(argvars);
799 }
800 
801 /*
802  * "assert_match(pattern, actual[, msg])" function
803  */
804     void
805 f_assert_match(typval_T *argvars, typval_T *rettv)
806 {
807     rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
808 }
809 
810 /*
811  * "assert_notmatch(pattern, actual[, msg])" function
812  */
813     void
814 f_assert_notmatch(typval_T *argvars, typval_T *rettv)
815 {
816     rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
817 }
818 
819 /*
820  * "assert_report(msg)" function
821  */
822     void
823 f_assert_report(typval_T *argvars, typval_T *rettv)
824 {
825     garray_T	ga;
826 
827     prepare_assert_error(&ga);
828     ga_concat(&ga, tv_get_string(&argvars[0]));
829     assert_error(&ga);
830     ga_clear(&ga);
831     rettv->vval.v_number = 1;
832 }
833 
834 /*
835  * "assert_true(actual[, msg])" function
836  */
837     void
838 f_assert_true(typval_T *argvars, typval_T *rettv)
839 {
840     rettv->vval.v_number = assert_bool(argvars, TRUE);
841 }
842 
843 /*
844  * "test_alloc_fail(id, countdown, repeat)" function
845  */
846     void
847 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
848 {
849     if (argvars[0].v_type != VAR_NUMBER
850 	    || argvars[0].vval.v_number <= 0
851 	    || argvars[1].v_type != VAR_NUMBER
852 	    || argvars[1].vval.v_number < 0
853 	    || argvars[2].v_type != VAR_NUMBER)
854 	emsg(_(e_invarg));
855     else
856     {
857 	alloc_fail_id = argvars[0].vval.v_number;
858 	if (alloc_fail_id >= aid_last)
859 	    emsg(_(e_invarg));
860 	alloc_fail_countdown = argvars[1].vval.v_number;
861 	alloc_fail_repeat = argvars[2].vval.v_number;
862 	did_outofmem_msg = FALSE;
863     }
864 }
865 
866 /*
867  * "test_autochdir()"
868  */
869     void
870 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
871 {
872 #if defined(FEAT_AUTOCHDIR)
873     test_autochdir = TRUE;
874 #endif
875 }
876 
877 /*
878  * "test_feedinput()"
879  */
880     void
881 f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
882 {
883 #ifdef USE_INPUT_BUF
884     char_u	*val = tv_get_string_chk(&argvars[0]);
885 
886 # ifdef VIMDLL
887     // this doesn't work in the console
888     if (!gui.in_use)
889 	return;
890 # endif
891 
892     if (val != NULL)
893     {
894 	trash_input_buf();
895 	add_to_input_buf_csi(val, (int)STRLEN(val));
896     }
897 #endif
898 }
899 
900 /*
901  * "test_getvalue({name})" function
902  */
903     void
904 f_test_getvalue(typval_T *argvars, typval_T *rettv)
905 {
906     if (argvars[0].v_type != VAR_STRING)
907 	emsg(_(e_invarg));
908     else
909     {
910 	char_u *name = tv_get_string(&argvars[0]);
911 
912 	if (STRCMP(name, (char_u *)"need_fileinfo") == 0)
913 	    rettv->vval.v_number = need_fileinfo;
914 	else
915 	    semsg(_(e_invarg2), name);
916     }
917 }
918 
919 /*
920  * "test_option_not_set({name})" function
921  */
922     void
923 f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
924 {
925     char_u *name = (char_u *)"";
926 
927     if (argvars[0].v_type != VAR_STRING)
928 	emsg(_(e_invarg));
929     else
930     {
931 	name = tv_get_string(&argvars[0]);
932 	if (reset_option_was_set(name) == FAIL)
933 	    semsg(_(e_invarg2), name);
934     }
935 }
936 
937 /*
938  * "test_override({name}, {val})" function
939  */
940     void
941 f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
942 {
943     char_u *name = (char_u *)"";
944     int     val;
945     static int save_starting = -1;
946 
947     if (argvars[0].v_type != VAR_STRING
948 	    || (argvars[1].v_type) != VAR_NUMBER)
949 	emsg(_(e_invarg));
950     else
951     {
952 	name = tv_get_string(&argvars[0]);
953 	val = (int)tv_get_number(&argvars[1]);
954 
955 	if (STRCMP(name, (char_u *)"redraw") == 0)
956 	    disable_redraw_for_testing = val;
957 	else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
958 	    ignore_redraw_flag_for_testing = val;
959 	else if (STRCMP(name, (char_u *)"char_avail") == 0)
960 	    disable_char_avail_for_testing = val;
961 	else if (STRCMP(name, (char_u *)"starting") == 0)
962 	{
963 	    if (val)
964 	    {
965 		if (save_starting < 0)
966 		    save_starting = starting;
967 		starting = 0;
968 	    }
969 	    else
970 	    {
971 		starting = save_starting;
972 		save_starting = -1;
973 	    }
974 	}
975 	else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
976 	    nfa_fail_for_testing = val;
977 	else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
978 	    no_query_mouse_for_testing = val;
979 	else if (STRCMP(name, (char_u *)"no_wait_return") == 0)
980 	    no_wait_return = val;
981 	else if (STRCMP(name, (char_u *)"ui_delay") == 0)
982 	    ui_delay_for_testing = val;
983 	else if (STRCMP(name, (char_u *)"term_props") == 0)
984 	    reset_term_props_on_termresponse = val;
985 	else if (STRCMP(name, (char_u *)"uptime") == 0)
986 	    override_sysinfo_uptime = val;
987 	else if (STRCMP(name, (char_u *)"ALL") == 0)
988 	{
989 	    disable_char_avail_for_testing = FALSE;
990 	    disable_redraw_for_testing = FALSE;
991 	    ignore_redraw_flag_for_testing = FALSE;
992 	    nfa_fail_for_testing = FALSE;
993 	    no_query_mouse_for_testing = FALSE;
994 	    ui_delay_for_testing = 0;
995 	    reset_term_props_on_termresponse = FALSE;
996 	    override_sysinfo_uptime = -1;
997 	    if (save_starting >= 0)
998 	    {
999 		starting = save_starting;
1000 		save_starting = -1;
1001 	    }
1002 	}
1003 	else
1004 	    semsg(_(e_invarg2), name);
1005     }
1006 }
1007 
1008 /*
1009  * "test_refcount({expr})" function
1010  */
1011     void
1012 f_test_refcount(typval_T *argvars, typval_T *rettv)
1013 {
1014     int retval = -1;
1015 
1016     switch (argvars[0].v_type)
1017     {
1018 	case VAR_UNKNOWN:
1019 	case VAR_ANY:
1020 	case VAR_VOID:
1021 	case VAR_NUMBER:
1022 	case VAR_BOOL:
1023 	case VAR_FLOAT:
1024 	case VAR_SPECIAL:
1025 	case VAR_STRING:
1026 	    break;
1027 	case VAR_JOB:
1028 #ifdef FEAT_JOB_CHANNEL
1029 	    if (argvars[0].vval.v_job != NULL)
1030 		retval = argvars[0].vval.v_job->jv_refcount - 1;
1031 #endif
1032 	    break;
1033 	case VAR_CHANNEL:
1034 #ifdef FEAT_JOB_CHANNEL
1035 	    if (argvars[0].vval.v_channel != NULL)
1036 		retval = argvars[0].vval.v_channel->ch_refcount - 1;
1037 #endif
1038 	    break;
1039 	case VAR_FUNC:
1040 	    if (argvars[0].vval.v_string != NULL)
1041 	    {
1042 		ufunc_T *fp;
1043 
1044 		fp = find_func(argvars[0].vval.v_string, FALSE, NULL);
1045 		if (fp != NULL)
1046 		    retval = fp->uf_refcount;
1047 	    }
1048 	    break;
1049 	case VAR_PARTIAL:
1050 	    if (argvars[0].vval.v_partial != NULL)
1051 		retval = argvars[0].vval.v_partial->pt_refcount - 1;
1052 	    break;
1053 	case VAR_BLOB:
1054 	    if (argvars[0].vval.v_blob != NULL)
1055 		retval = argvars[0].vval.v_blob->bv_refcount - 1;
1056 	    break;
1057 	case VAR_LIST:
1058 	    if (argvars[0].vval.v_list != NULL)
1059 		retval = argvars[0].vval.v_list->lv_refcount - 1;
1060 	    break;
1061 	case VAR_DICT:
1062 	    if (argvars[0].vval.v_dict != NULL)
1063 		retval = argvars[0].vval.v_dict->dv_refcount - 1;
1064 	    break;
1065     }
1066 
1067     rettv->v_type = VAR_NUMBER;
1068     rettv->vval.v_number = retval;
1069 
1070 }
1071 
1072 /*
1073  * "test_garbagecollect_now()" function
1074  */
1075     void
1076 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1077 {
1078     // This is dangerous, any Lists and Dicts used internally may be freed
1079     // while still in use.
1080     garbage_collect(TRUE);
1081 }
1082 
1083 /*
1084  * "test_garbagecollect_soon()" function
1085  */
1086     void
1087 f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1088 {
1089     may_garbage_collect = TRUE;
1090 }
1091 
1092 /*
1093  * "test_ignore_error()" function
1094  */
1095     void
1096 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
1097 {
1098      ignore_error_for_testing(tv_get_string(&argvars[0]));
1099 }
1100 
1101     void
1102 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
1103 {
1104     rettv->v_type = VAR_BLOB;
1105     rettv->vval.v_blob = NULL;
1106 }
1107 
1108 #ifdef FEAT_JOB_CHANNEL
1109     void
1110 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
1111 {
1112     rettv->v_type = VAR_CHANNEL;
1113     rettv->vval.v_channel = NULL;
1114 }
1115 #endif
1116 
1117     void
1118 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
1119 {
1120     rettv_dict_set(rettv, NULL);
1121 }
1122 
1123 #ifdef FEAT_JOB_CHANNEL
1124     void
1125 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
1126 {
1127     rettv->v_type = VAR_JOB;
1128     rettv->vval.v_job = NULL;
1129 }
1130 #endif
1131 
1132     void
1133 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
1134 {
1135     rettv_list_set(rettv, NULL);
1136 }
1137 
1138     void
1139 f_test_null_function(typval_T *argvars UNUSED, typval_T *rettv)
1140 {
1141     rettv->v_type = VAR_FUNC;
1142     rettv->vval.v_string = NULL;
1143 }
1144 
1145     void
1146 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
1147 {
1148     rettv->v_type = VAR_PARTIAL;
1149     rettv->vval.v_partial = NULL;
1150 }
1151 
1152     void
1153 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
1154 {
1155     rettv->v_type = VAR_STRING;
1156     rettv->vval.v_string = NULL;
1157 }
1158 
1159     void
1160 f_test_unknown(typval_T *argvars UNUSED, typval_T *rettv)
1161 {
1162     rettv->v_type = VAR_UNKNOWN;
1163 }
1164 
1165     void
1166 f_test_void(typval_T *argvars UNUSED, typval_T *rettv)
1167 {
1168     rettv->v_type = VAR_VOID;
1169 }
1170 
1171 #ifdef FEAT_GUI
1172     void
1173 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
1174 {
1175     char_u	*which;
1176     long	value;
1177     int		dragging;
1178     scrollbar_T *sb = NULL;
1179 
1180     if (argvars[0].v_type != VAR_STRING
1181 	    || (argvars[1].v_type) != VAR_NUMBER
1182 	    || (argvars[2].v_type) != VAR_NUMBER)
1183     {
1184 	emsg(_(e_invarg));
1185 	return;
1186     }
1187     which = tv_get_string(&argvars[0]);
1188     value = tv_get_number(&argvars[1]);
1189     dragging = tv_get_number(&argvars[2]);
1190 
1191     if (STRCMP(which, "left") == 0)
1192 	sb = &curwin->w_scrollbars[SBAR_LEFT];
1193     else if (STRCMP(which, "right") == 0)
1194 	sb = &curwin->w_scrollbars[SBAR_RIGHT];
1195     else if (STRCMP(which, "hor") == 0)
1196 	sb = &gui.bottom_sbar;
1197     if (sb == NULL)
1198     {
1199 	semsg(_(e_invarg2), which);
1200 	return;
1201     }
1202     gui_drag_scrollbar(sb, value, dragging);
1203 # ifndef USE_ON_FLY_SCROLL
1204     // need to loop through normal_cmd() to handle the scroll events
1205     exec_normal(FALSE, TRUE, FALSE);
1206 # endif
1207 }
1208 #endif
1209 
1210     void
1211 f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
1212 {
1213     mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
1214     mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
1215 }
1216 
1217     void
1218 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
1219 {
1220     time_for_testing = (time_t)tv_get_number(&argvars[0]);
1221 }
1222 
1223 
1224 #endif // defined(FEAT_EVAL)
1225