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 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 377 f_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 386 f_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 395 f_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 424 f_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; 429 int called_emsg_before = called_emsg; 430 431 // trylevel must be zero for a ":throw" command to be considered failed 432 trylevel = 0; 433 suppress_errthrow = TRUE; 434 emsg_silent = TRUE; 435 436 do_cmdline_cmd(cmd); 437 if (called_emsg == called_emsg_before) 438 { 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; 466 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 476 f_assert_false(typval_T *argvars, typval_T *rettv) 477 { 478 rettv->vval.v_number = assert_bool(argvars, FALSE); 479 } 480 481 static int 482 assert_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 553 f_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 562 f_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 571 f_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 580 f_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 595 f_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 604 f_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 627 f_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 638 f_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 655 f_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 674 f_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 692 f_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 754 f_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_BOOL: 764 case VAR_SPECIAL: 765 case VAR_STRING: 766 break; 767 case VAR_JOB: 768 #ifdef FEAT_JOB_CHANNEL 769 if (argvars[0].vval.v_job != NULL) 770 retval = argvars[0].vval.v_job->jv_refcount - 1; 771 #endif 772 break; 773 case VAR_CHANNEL: 774 #ifdef FEAT_JOB_CHANNEL 775 if (argvars[0].vval.v_channel != NULL) 776 retval = argvars[0].vval.v_channel->ch_refcount - 1; 777 #endif 778 break; 779 case VAR_FUNC: 780 if (argvars[0].vval.v_string != NULL) 781 { 782 ufunc_T *fp; 783 784 fp = find_func(argvars[0].vval.v_string); 785 if (fp != NULL) 786 retval = fp->uf_refcount; 787 } 788 break; 789 case VAR_PARTIAL: 790 if (argvars[0].vval.v_partial != NULL) 791 retval = argvars[0].vval.v_partial->pt_refcount - 1; 792 break; 793 case VAR_BLOB: 794 if (argvars[0].vval.v_blob != NULL) 795 retval = argvars[0].vval.v_blob->bv_refcount - 1; 796 break; 797 case VAR_LIST: 798 if (argvars[0].vval.v_list != NULL) 799 retval = argvars[0].vval.v_list->lv_refcount - 1; 800 break; 801 case VAR_DICT: 802 if (argvars[0].vval.v_dict != NULL) 803 retval = argvars[0].vval.v_dict->dv_refcount - 1; 804 break; 805 } 806 807 rettv->v_type = VAR_NUMBER; 808 rettv->vval.v_number = retval; 809 810 } 811 812 /* 813 * "test_garbagecollect_now()" function 814 */ 815 void 816 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 817 { 818 // This is dangerous, any Lists and Dicts used internally may be freed 819 // while still in use. 820 garbage_collect(TRUE); 821 } 822 823 /* 824 * "test_garbagecollect_soon()" function 825 */ 826 void 827 f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 828 { 829 may_garbage_collect = TRUE; 830 } 831 832 /* 833 * "test_ignore_error()" function 834 */ 835 void 836 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED) 837 { 838 ignore_error_for_testing(tv_get_string(&argvars[0])); 839 } 840 841 void 842 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv) 843 { 844 rettv->v_type = VAR_BLOB; 845 rettv->vval.v_blob = NULL; 846 } 847 848 #ifdef FEAT_JOB_CHANNEL 849 void 850 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) 851 { 852 rettv->v_type = VAR_CHANNEL; 853 rettv->vval.v_channel = NULL; 854 } 855 #endif 856 857 void 858 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) 859 { 860 rettv_dict_set(rettv, NULL); 861 } 862 863 #ifdef FEAT_JOB_CHANNEL 864 void 865 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) 866 { 867 rettv->v_type = VAR_JOB; 868 rettv->vval.v_job = NULL; 869 } 870 #endif 871 872 void 873 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) 874 { 875 rettv_list_set(rettv, NULL); 876 } 877 878 void 879 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) 880 { 881 rettv->v_type = VAR_PARTIAL; 882 rettv->vval.v_partial = NULL; 883 } 884 885 void 886 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) 887 { 888 rettv->v_type = VAR_STRING; 889 rettv->vval.v_string = NULL; 890 } 891 892 #ifdef FEAT_GUI 893 void 894 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED) 895 { 896 char_u *which; 897 long value; 898 int dragging; 899 scrollbar_T *sb = NULL; 900 901 if (argvars[0].v_type != VAR_STRING 902 || (argvars[1].v_type) != VAR_NUMBER 903 || (argvars[2].v_type) != VAR_NUMBER) 904 { 905 emsg(_(e_invarg)); 906 return; 907 } 908 which = tv_get_string(&argvars[0]); 909 value = tv_get_number(&argvars[1]); 910 dragging = tv_get_number(&argvars[2]); 911 912 if (STRCMP(which, "left") == 0) 913 sb = &curwin->w_scrollbars[SBAR_LEFT]; 914 else if (STRCMP(which, "right") == 0) 915 sb = &curwin->w_scrollbars[SBAR_RIGHT]; 916 else if (STRCMP(which, "hor") == 0) 917 sb = &gui.bottom_sbar; 918 if (sb == NULL) 919 { 920 semsg(_(e_invarg2), which); 921 return; 922 } 923 gui_drag_scrollbar(sb, value, dragging); 924 # ifndef USE_ON_FLY_SCROLL 925 // need to loop through normal_cmd() to handle the scroll events 926 exec_normal(FALSE, TRUE, FALSE); 927 # endif 928 } 929 #endif 930 931 void 932 f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED) 933 { 934 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1; 935 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1; 936 } 937 938 void 939 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) 940 { 941 time_for_testing = (time_t)tv_get_number(&argvars[0]); 942 } 943 944 945 #endif // defined(FEAT_EVAL) 946