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