blob: 3e6ba8e03e9c9c460f6d869652ff935a23444b39 [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];
25 char_u *sname = estack_sfile();
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:
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
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,
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
175assert_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
193assert_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
220assert_bool(typval_T *argvars, int isTrue)
221{
222 int error = FALSE;
223 garray_T ga;
224
225 if (argvars[0].v_type == VAR_SPECIAL
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
244assert_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
259assert_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
288f_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
297f_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
303assert_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
313 if (fname1 == NULL || fname2 == NULL)
314 return 0;
315
316 IObuff[0] = NUL;
317 fd1 = mch_fopen((char *)fname1, READBIN);
318 if (fd1 == NULL)
319 {
320 vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname1);
321 }
322 else
323 {
324 fd2 = mch_fopen((char *)fname2, READBIN);
325 if (fd2 == NULL)
326 {
327 fclose(fd1);
328 vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
329 }
330 else
331 {
332 int c1, c2;
333 long count = 0;
334
335 for (;;)
336 {
337 c1 = fgetc(fd1);
338 c2 = fgetc(fd2);
339 if (c1 == EOF)
340 {
341 if (c2 != EOF)
342 STRCPY(IObuff, "first file is shorter");
343 break;
344 }
345 else if (c2 == EOF)
346 {
347 STRCPY(IObuff, "second file is shorter");
348 break;
349 }
350 else if (c1 != c2)
351 {
352 vim_snprintf((char *)IObuff, IOSIZE,
353 "difference at byte %ld", count);
354 break;
355 }
356 ++count;
357 }
358 fclose(fd1);
359 fclose(fd2);
360 }
361 }
362 if (IObuff[0] != NUL)
363 {
364 prepare_assert_error(&ga);
365 ga_concat(&ga, IObuff);
366 assert_error(&ga);
367 ga_clear(&ga);
368 return 1;
369 }
370 return 0;
371}
372
373/*
374 * "assert_equalfile(fname-one, fname-two)" function
375 */
376 void
377f_assert_equalfile(typval_T *argvars, typval_T *rettv)
378{
379 rettv->vval.v_number = assert_equalfile(argvars);
380}
381
382/*
383 * "assert_notequal(expected, actual[, msg])" function
384 */
385 void
386f_assert_notequal(typval_T *argvars, typval_T *rettv)
387{
388 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
389}
390
391/*
392 * "assert_exception(string[, msg])" function
393 */
394 void
395f_assert_exception(typval_T *argvars, typval_T *rettv)
396{
397 garray_T ga;
398 char_u *error = tv_get_string_chk(&argvars[0]);
399
400 if (*get_vim_var_str(VV_EXCEPTION) == NUL)
401 {
402 prepare_assert_error(&ga);
403 ga_concat(&ga, (char_u *)"v:exception is not set");
404 assert_error(&ga);
405 ga_clear(&ga);
406 rettv->vval.v_number = 1;
407 }
408 else if (error != NULL
409 && strstr((char *)get_vim_var_str(VV_EXCEPTION), (char *)error) == NULL)
410 {
411 prepare_assert_error(&ga);
412 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
413 get_vim_var_tv(VV_EXCEPTION), ASSERT_OTHER);
414 assert_error(&ga);
415 ga_clear(&ga);
416 rettv->vval.v_number = 1;
417 }
418}
419
420/*
421 * "assert_fails(cmd [, error[, msg]])" function
422 */
423 void
424f_assert_fails(typval_T *argvars, typval_T *rettv)
425{
426 char_u *cmd = tv_get_string_chk(&argvars[0]);
427 garray_T ga;
428 int save_trylevel = trylevel;
Bram Moolenaar53989552019-12-23 22:59:18 +0100429 int called_emsg_before = called_emsg;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200430
431 // trylevel must be zero for a ":throw" command to be considered failed
432 trylevel = 0;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200433 suppress_errthrow = TRUE;
434 emsg_silent = TRUE;
435
436 do_cmdline_cmd(cmd);
Bram Moolenaar53989552019-12-23 22:59:18 +0100437 if (called_emsg == called_emsg_before)
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200438 {
439 prepare_assert_error(&ga);
440 ga_concat(&ga, (char_u *)"command did not fail: ");
441 assert_append_cmd_or_arg(&ga, argvars, cmd);
442 assert_error(&ga);
443 ga_clear(&ga);
444 rettv->vval.v_number = 1;
445 }
446 else if (argvars[1].v_type != VAR_UNKNOWN)
447 {
448 char_u buf[NUMBUFLEN];
449 char *error = (char *)tv_get_string_buf_chk(&argvars[1], buf);
450
451 if (error == NULL
452 || strstr((char *)get_vim_var_str(VV_ERRMSG), error) == NULL)
453 {
454 prepare_assert_error(&ga);
455 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
456 get_vim_var_tv(VV_ERRMSG), ASSERT_OTHER);
457 ga_concat(&ga, (char_u *)": ");
458 assert_append_cmd_or_arg(&ga, argvars, cmd);
459 assert_error(&ga);
460 ga_clear(&ga);
461 rettv->vval.v_number = 1;
462 }
463 }
464
465 trylevel = save_trylevel;
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200466 suppress_errthrow = FALSE;
467 emsg_silent = FALSE;
468 emsg_on_display = FALSE;
469 set_vim_var_string(VV_ERRMSG, NULL, 0);
470}
471
472/*
473 * "assert_false(actual[, msg])" function
474 */
475 void
476f_assert_false(typval_T *argvars, typval_T *rettv)
477{
478 rettv->vval.v_number = assert_bool(argvars, FALSE);
479}
480
481 static int
482assert_inrange(typval_T *argvars)
483{
484 garray_T ga;
485 int error = FALSE;
486 char_u *tofree;
487 char msg[200];
488 char_u numbuf[NUMBUFLEN];
489
490#ifdef FEAT_FLOAT
491 if (argvars[0].v_type == VAR_FLOAT
492 || argvars[1].v_type == VAR_FLOAT
493 || argvars[2].v_type == VAR_FLOAT)
494 {
495 float_T flower = tv_get_float(&argvars[0]);
496 float_T fupper = tv_get_float(&argvars[1]);
497 float_T factual = tv_get_float(&argvars[2]);
498
499 if (factual < flower || factual > fupper)
500 {
501 prepare_assert_error(&ga);
502 if (argvars[3].v_type != VAR_UNKNOWN)
503 {
504 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
505 vim_free(tofree);
506 }
507 else
508 {
509 vim_snprintf(msg, 200, "Expected range %g - %g, but got %g",
510 flower, fupper, factual);
511 ga_concat(&ga, (char_u *)msg);
512 }
513 assert_error(&ga);
514 ga_clear(&ga);
515 return 1;
516 }
517 }
518 else
519#endif
520 {
521 varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
522 varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
523 varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
524
525 if (error)
526 return 0;
527 if (actual < lower || actual > upper)
528 {
529 prepare_assert_error(&ga);
530 if (argvars[3].v_type != VAR_UNKNOWN)
531 {
532 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
533 vim_free(tofree);
534 }
535 else
536 {
537 vim_snprintf(msg, 200, "Expected range %ld - %ld, but got %ld",
538 (long)lower, (long)upper, (long)actual);
539 ga_concat(&ga, (char_u *)msg);
540 }
541 assert_error(&ga);
542 ga_clear(&ga);
543 return 1;
544 }
545 }
546 return 0;
547}
548
549/*
550 * "assert_inrange(lower, upper[, msg])" function
551 */
552 void
553f_assert_inrange(typval_T *argvars, typval_T *rettv)
554{
555 rettv->vval.v_number = assert_inrange(argvars);
556}
557
558/*
559 * "assert_match(pattern, actual[, msg])" function
560 */
561 void
562f_assert_match(typval_T *argvars, typval_T *rettv)
563{
564 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
565}
566
567/*
568 * "assert_notmatch(pattern, actual[, msg])" function
569 */
570 void
571f_assert_notmatch(typval_T *argvars, typval_T *rettv)
572{
573 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
574}
575
576/*
577 * "assert_report(msg)" function
578 */
579 void
580f_assert_report(typval_T *argvars, typval_T *rettv)
581{
582 garray_T ga;
583
584 prepare_assert_error(&ga);
585 ga_concat(&ga, tv_get_string(&argvars[0]));
586 assert_error(&ga);
587 ga_clear(&ga);
588 rettv->vval.v_number = 1;
589}
590
591/*
592 * "assert_true(actual[, msg])" function
593 */
594 void
595f_assert_true(typval_T *argvars, typval_T *rettv)
596{
597 rettv->vval.v_number = assert_bool(argvars, TRUE);
598}
599
600/*
601 * "test_alloc_fail(id, countdown, repeat)" function
602 */
603 void
604f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
605{
606 if (argvars[0].v_type != VAR_NUMBER
607 || argvars[0].vval.v_number <= 0
608 || argvars[1].v_type != VAR_NUMBER
609 || argvars[1].vval.v_number < 0
610 || argvars[2].v_type != VAR_NUMBER)
611 emsg(_(e_invarg));
612 else
613 {
614 alloc_fail_id = argvars[0].vval.v_number;
615 if (alloc_fail_id >= aid_last)
616 emsg(_(e_invarg));
617 alloc_fail_countdown = argvars[1].vval.v_number;
618 alloc_fail_repeat = argvars[2].vval.v_number;
619 did_outofmem_msg = FALSE;
620 }
621}
622
623/*
624 * "test_autochdir()"
625 */
626 void
627f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
628{
629#if defined(FEAT_AUTOCHDIR)
630 test_autochdir = TRUE;
631#endif
632}
633
634/*
635 * "test_feedinput()"
636 */
637 void
638f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
639{
640#ifdef USE_INPUT_BUF
641 char_u *val = tv_get_string_chk(&argvars[0]);
642
643 if (val != NULL)
644 {
645 trash_input_buf();
646 add_to_input_buf_csi(val, (int)STRLEN(val));
647 }
648#endif
649}
650
651/*
652 * "test_getvalue({name})" function
653 */
654 void
655f_test_getvalue(typval_T *argvars, typval_T *rettv)
656{
657 if (argvars[0].v_type != VAR_STRING)
658 emsg(_(e_invarg));
659 else
660 {
661 char_u *name = tv_get_string(&argvars[0]);
662
663 if (STRCMP(name, (char_u *)"need_fileinfo") == 0)
664 rettv->vval.v_number = need_fileinfo;
665 else
666 semsg(_(e_invarg2), name);
667 }
668}
669
670/*
671 * "test_option_not_set({name})" function
672 */
673 void
674f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
675{
676 char_u *name = (char_u *)"";
677
678 if (argvars[0].v_type != VAR_STRING)
679 emsg(_(e_invarg));
680 else
681 {
682 name = tv_get_string(&argvars[0]);
683 if (reset_option_was_set(name) == FAIL)
684 semsg(_(e_invarg2), name);
685 }
686}
687
688/*
689 * "test_override({name}, {val})" function
690 */
691 void
692f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
693{
694 char_u *name = (char_u *)"";
695 int val;
696 static int save_starting = -1;
697
698 if (argvars[0].v_type != VAR_STRING
699 || (argvars[1].v_type) != VAR_NUMBER)
700 emsg(_(e_invarg));
701 else
702 {
703 name = tv_get_string(&argvars[0]);
704 val = (int)tv_get_number(&argvars[1]);
705
706 if (STRCMP(name, (char_u *)"redraw") == 0)
707 disable_redraw_for_testing = val;
708 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
709 ignore_redraw_flag_for_testing = val;
710 else if (STRCMP(name, (char_u *)"char_avail") == 0)
711 disable_char_avail_for_testing = val;
712 else if (STRCMP(name, (char_u *)"starting") == 0)
713 {
714 if (val)
715 {
716 if (save_starting < 0)
717 save_starting = starting;
718 starting = 0;
719 }
720 else
721 {
722 starting = save_starting;
723 save_starting = -1;
724 }
725 }
726 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
727 nfa_fail_for_testing = val;
728 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
729 no_query_mouse_for_testing = val;
730 else if (STRCMP(name, (char_u *)"no_wait_return") == 0)
731 no_wait_return = val;
732 else if (STRCMP(name, (char_u *)"ALL") == 0)
733 {
734 disable_char_avail_for_testing = FALSE;
735 disable_redraw_for_testing = FALSE;
736 ignore_redraw_flag_for_testing = FALSE;
737 nfa_fail_for_testing = FALSE;
738 no_query_mouse_for_testing = FALSE;
739 if (save_starting >= 0)
740 {
741 starting = save_starting;
742 save_starting = -1;
743 }
744 }
745 else
746 semsg(_(e_invarg2), name);
747 }
748}
749
750/*
751 * "test_refcount({expr})" function
752 */
753 void
754f_test_refcount(typval_T *argvars, typval_T *rettv)
755{
756 int retval = -1;
757
758 switch (argvars[0].v_type)
759 {
760 case VAR_UNKNOWN:
761 case VAR_NUMBER:
762 case VAR_FLOAT:
763 case VAR_SPECIAL:
764 case VAR_STRING:
765 break;
766 case VAR_JOB:
767#ifdef FEAT_JOB_CHANNEL
768 if (argvars[0].vval.v_job != NULL)
769 retval = argvars[0].vval.v_job->jv_refcount - 1;
770#endif
771 break;
772 case VAR_CHANNEL:
773#ifdef FEAT_JOB_CHANNEL
774 if (argvars[0].vval.v_channel != NULL)
775 retval = argvars[0].vval.v_channel->ch_refcount - 1;
776#endif
777 break;
778 case VAR_FUNC:
779 if (argvars[0].vval.v_string != NULL)
780 {
781 ufunc_T *fp;
782
783 fp = find_func(argvars[0].vval.v_string);
784 if (fp != NULL)
785 retval = fp->uf_refcount;
786 }
787 break;
788 case VAR_PARTIAL:
789 if (argvars[0].vval.v_partial != NULL)
790 retval = argvars[0].vval.v_partial->pt_refcount - 1;
791 break;
792 case VAR_BLOB:
793 if (argvars[0].vval.v_blob != NULL)
794 retval = argvars[0].vval.v_blob->bv_refcount - 1;
795 break;
796 case VAR_LIST:
797 if (argvars[0].vval.v_list != NULL)
798 retval = argvars[0].vval.v_list->lv_refcount - 1;
799 break;
800 case VAR_DICT:
801 if (argvars[0].vval.v_dict != NULL)
802 retval = argvars[0].vval.v_dict->dv_refcount - 1;
803 break;
804 }
805
806 rettv->v_type = VAR_NUMBER;
807 rettv->vval.v_number = retval;
808
809}
810
811/*
812 * "test_garbagecollect_now()" function
813 */
814 void
815f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
816{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100817 // This is dangerous, any Lists and Dicts used internally may be freed
818 // while still in use.
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200819 garbage_collect(TRUE);
820}
821
822/*
823 * "test_garbagecollect_soon()" function
824 */
825 void
826f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
827{
828 may_garbage_collect = TRUE;
829}
830
831/*
832 * "test_ignore_error()" function
833 */
834 void
835f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
836{
837 ignore_error_for_testing(tv_get_string(&argvars[0]));
838}
839
840 void
841f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
842{
843 rettv->v_type = VAR_BLOB;
844 rettv->vval.v_blob = NULL;
845}
846
847#ifdef FEAT_JOB_CHANNEL
848 void
849f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
850{
851 rettv->v_type = VAR_CHANNEL;
852 rettv->vval.v_channel = NULL;
853}
854#endif
855
856 void
857f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
858{
859 rettv_dict_set(rettv, NULL);
860}
861
862#ifdef FEAT_JOB_CHANNEL
863 void
864f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
865{
866 rettv->v_type = VAR_JOB;
867 rettv->vval.v_job = NULL;
868}
869#endif
870
871 void
872f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
873{
874 rettv_list_set(rettv, NULL);
875}
876
877 void
878f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
879{
880 rettv->v_type = VAR_PARTIAL;
881 rettv->vval.v_partial = NULL;
882}
883
884 void
885f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
886{
887 rettv->v_type = VAR_STRING;
888 rettv->vval.v_string = NULL;
889}
890
891#ifdef FEAT_GUI
892 void
893f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
894{
895 char_u *which;
896 long value;
897 int dragging;
898 scrollbar_T *sb = NULL;
899
900 if (argvars[0].v_type != VAR_STRING
901 || (argvars[1].v_type) != VAR_NUMBER
902 || (argvars[2].v_type) != VAR_NUMBER)
903 {
904 emsg(_(e_invarg));
905 return;
906 }
907 which = tv_get_string(&argvars[0]);
908 value = tv_get_number(&argvars[1]);
909 dragging = tv_get_number(&argvars[2]);
910
911 if (STRCMP(which, "left") == 0)
912 sb = &curwin->w_scrollbars[SBAR_LEFT];
913 else if (STRCMP(which, "right") == 0)
914 sb = &curwin->w_scrollbars[SBAR_RIGHT];
915 else if (STRCMP(which, "hor") == 0)
916 sb = &gui.bottom_sbar;
917 if (sb == NULL)
918 {
919 semsg(_(e_invarg2), which);
920 return;
921 }
922 gui_drag_scrollbar(sb, value, dragging);
923# ifndef USE_ON_FLY_SCROLL
924 // need to loop through normal_cmd() to handle the scroll events
925 exec_normal(FALSE, TRUE, FALSE);
926# endif
927}
928#endif
929
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200930 void
931f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
932{
933 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
934 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
935}
Bram Moolenaarecaa70e2019-07-14 14:55:39 +0200936
937 void
938f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
939{
940 time_for_testing = (time_t)tv_get_number(&argvars[0]);
941}
942
943
944#endif // defined(FEAT_EVAL)