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