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