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