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 int wrong_arg = FALSE; 550 551 // trylevel must be zero for a ":throw" command to be considered failed 552 trylevel = 0; 553 suppress_errthrow = TRUE; 554 emsg_silent = TRUE; 555 emsg_assert_fails_used = TRUE; 556 557 do_cmdline_cmd(cmd); 558 if (called_emsg == called_emsg_before) 559 { 560 prepare_assert_error(&ga); 561 ga_concat(&ga, (char_u *)"command did not fail: "); 562 assert_append_cmd_or_arg(&ga, argvars, cmd); 563 assert_error(&ga); 564 ga_clear(&ga); 565 rettv->vval.v_number = 1; 566 } 567 else if (argvars[1].v_type != VAR_UNKNOWN) 568 { 569 char_u buf[NUMBUFLEN]; 570 char_u *expected; 571 int error_found = FALSE; 572 char_u *actual = emsg_assert_fails_msg == NULL ? (char_u *)"[unknown]" 573 : emsg_assert_fails_msg; 574 575 if (argvars[1].v_type == VAR_STRING) 576 { 577 expected = tv_get_string_buf_chk(&argvars[1], buf); 578 error_found = expected == NULL 579 || strstr((char *)actual, (char *)expected) == NULL; 580 } 581 else if (argvars[1].v_type == VAR_LIST) 582 { 583 list_T *list = argvars[1].vval.v_list; 584 typval_T *tv; 585 586 if (list == NULL || list->lv_len < 1 || list->lv_len > 2) 587 { 588 wrong_arg = TRUE; 589 goto theend; 590 } 591 CHECK_LIST_MATERIALIZE(list); 592 tv = &list->lv_first->li_tv; 593 expected = tv_get_string_buf_chk(tv, buf); 594 if (!pattern_match(expected, actual, FALSE)) 595 { 596 error_found = TRUE; 597 } 598 else if (list->lv_len == 2) 599 { 600 tv = &list->lv_u.mat.lv_last->li_tv; 601 actual = get_vim_var_str(VV_ERRMSG); 602 expected = tv_get_string_buf_chk(tv, buf); 603 if (!pattern_match(expected, actual, FALSE)) 604 error_found = TRUE; 605 } 606 } 607 else 608 { 609 wrong_arg = TRUE; 610 goto theend; 611 } 612 613 if (error_found) 614 { 615 typval_T actual_tv; 616 617 prepare_assert_error(&ga); 618 actual_tv.v_type = VAR_STRING; 619 actual_tv.vval.v_string = actual; 620 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], 621 &actual_tv, ASSERT_OTHER); 622 ga_concat(&ga, (char_u *)": "); 623 assert_append_cmd_or_arg(&ga, argvars, cmd); 624 assert_error(&ga); 625 ga_clear(&ga); 626 rettv->vval.v_number = 1; 627 } 628 } 629 630 theend: 631 trylevel = save_trylevel; 632 suppress_errthrow = FALSE; 633 emsg_silent = FALSE; 634 emsg_on_display = FALSE; 635 emsg_assert_fails_used = FALSE; 636 VIM_CLEAR(emsg_assert_fails_msg); 637 set_vim_var_string(VV_ERRMSG, NULL, 0); 638 if (wrong_arg) 639 emsg(_("E856: assert_fails() second argument must be a string or a list with one or two strings")); 640 } 641 642 /* 643 * "assert_false(actual[, msg])" function 644 */ 645 void 646 f_assert_false(typval_T *argvars, typval_T *rettv) 647 { 648 rettv->vval.v_number = assert_bool(argvars, FALSE); 649 } 650 651 static int 652 assert_inrange(typval_T *argvars) 653 { 654 garray_T ga; 655 int error = FALSE; 656 char_u *tofree; 657 char msg[200]; 658 char_u numbuf[NUMBUFLEN]; 659 660 #ifdef FEAT_FLOAT 661 if (argvars[0].v_type == VAR_FLOAT 662 || argvars[1].v_type == VAR_FLOAT 663 || argvars[2].v_type == VAR_FLOAT) 664 { 665 float_T flower = tv_get_float(&argvars[0]); 666 float_T fupper = tv_get_float(&argvars[1]); 667 float_T factual = tv_get_float(&argvars[2]); 668 669 if (factual < flower || factual > fupper) 670 { 671 prepare_assert_error(&ga); 672 if (argvars[3].v_type != VAR_UNKNOWN) 673 { 674 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0)); 675 vim_free(tofree); 676 } 677 else 678 { 679 vim_snprintf(msg, 200, "Expected range %g - %g, but got %g", 680 flower, fupper, factual); 681 ga_concat(&ga, (char_u *)msg); 682 } 683 assert_error(&ga); 684 ga_clear(&ga); 685 return 1; 686 } 687 } 688 else 689 #endif 690 { 691 varnumber_T lower = tv_get_number_chk(&argvars[0], &error); 692 varnumber_T upper = tv_get_number_chk(&argvars[1], &error); 693 varnumber_T actual = tv_get_number_chk(&argvars[2], &error); 694 695 if (error) 696 return 0; 697 if (actual < lower || actual > upper) 698 { 699 prepare_assert_error(&ga); 700 if (argvars[3].v_type != VAR_UNKNOWN) 701 { 702 ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0)); 703 vim_free(tofree); 704 } 705 else 706 { 707 vim_snprintf(msg, 200, "Expected range %ld - %ld, but got %ld", 708 (long)lower, (long)upper, (long)actual); 709 ga_concat(&ga, (char_u *)msg); 710 } 711 assert_error(&ga); 712 ga_clear(&ga); 713 return 1; 714 } 715 } 716 return 0; 717 } 718 719 /* 720 * "assert_inrange(lower, upper[, msg])" function 721 */ 722 void 723 f_assert_inrange(typval_T *argvars, typval_T *rettv) 724 { 725 rettv->vval.v_number = assert_inrange(argvars); 726 } 727 728 /* 729 * "assert_match(pattern, actual[, msg])" function 730 */ 731 void 732 f_assert_match(typval_T *argvars, typval_T *rettv) 733 { 734 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH); 735 } 736 737 /* 738 * "assert_notmatch(pattern, actual[, msg])" function 739 */ 740 void 741 f_assert_notmatch(typval_T *argvars, typval_T *rettv) 742 { 743 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH); 744 } 745 746 /* 747 * "assert_report(msg)" function 748 */ 749 void 750 f_assert_report(typval_T *argvars, typval_T *rettv) 751 { 752 garray_T ga; 753 754 prepare_assert_error(&ga); 755 ga_concat(&ga, tv_get_string(&argvars[0])); 756 assert_error(&ga); 757 ga_clear(&ga); 758 rettv->vval.v_number = 1; 759 } 760 761 /* 762 * "assert_true(actual[, msg])" function 763 */ 764 void 765 f_assert_true(typval_T *argvars, typval_T *rettv) 766 { 767 rettv->vval.v_number = assert_bool(argvars, TRUE); 768 } 769 770 /* 771 * "test_alloc_fail(id, countdown, repeat)" function 772 */ 773 void 774 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) 775 { 776 if (argvars[0].v_type != VAR_NUMBER 777 || argvars[0].vval.v_number <= 0 778 || argvars[1].v_type != VAR_NUMBER 779 || argvars[1].vval.v_number < 0 780 || argvars[2].v_type != VAR_NUMBER) 781 emsg(_(e_invarg)); 782 else 783 { 784 alloc_fail_id = argvars[0].vval.v_number; 785 if (alloc_fail_id >= aid_last) 786 emsg(_(e_invarg)); 787 alloc_fail_countdown = argvars[1].vval.v_number; 788 alloc_fail_repeat = argvars[2].vval.v_number; 789 did_outofmem_msg = FALSE; 790 } 791 } 792 793 /* 794 * "test_autochdir()" 795 */ 796 void 797 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 798 { 799 #if defined(FEAT_AUTOCHDIR) 800 test_autochdir = TRUE; 801 #endif 802 } 803 804 /* 805 * "test_feedinput()" 806 */ 807 void 808 f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED) 809 { 810 #ifdef USE_INPUT_BUF 811 char_u *val = tv_get_string_chk(&argvars[0]); 812 813 # ifdef VIMDLL 814 // this doesn't work in the console 815 if (!gui.in_use) 816 return; 817 # endif 818 819 if (val != NULL) 820 { 821 trash_input_buf(); 822 add_to_input_buf_csi(val, (int)STRLEN(val)); 823 } 824 #endif 825 } 826 827 /* 828 * "test_getvalue({name})" function 829 */ 830 void 831 f_test_getvalue(typval_T *argvars, typval_T *rettv) 832 { 833 if (argvars[0].v_type != VAR_STRING) 834 emsg(_(e_invarg)); 835 else 836 { 837 char_u *name = tv_get_string(&argvars[0]); 838 839 if (STRCMP(name, (char_u *)"need_fileinfo") == 0) 840 rettv->vval.v_number = need_fileinfo; 841 else 842 semsg(_(e_invarg2), name); 843 } 844 } 845 846 /* 847 * "test_option_not_set({name})" function 848 */ 849 void 850 f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED) 851 { 852 char_u *name = (char_u *)""; 853 854 if (argvars[0].v_type != VAR_STRING) 855 emsg(_(e_invarg)); 856 else 857 { 858 name = tv_get_string(&argvars[0]); 859 if (reset_option_was_set(name) == FAIL) 860 semsg(_(e_invarg2), name); 861 } 862 } 863 864 /* 865 * "test_override({name}, {val})" function 866 */ 867 void 868 f_test_override(typval_T *argvars, typval_T *rettv UNUSED) 869 { 870 char_u *name = (char_u *)""; 871 int val; 872 static int save_starting = -1; 873 874 if (argvars[0].v_type != VAR_STRING 875 || (argvars[1].v_type) != VAR_NUMBER) 876 emsg(_(e_invarg)); 877 else 878 { 879 name = tv_get_string(&argvars[0]); 880 val = (int)tv_get_number(&argvars[1]); 881 882 if (STRCMP(name, (char_u *)"redraw") == 0) 883 disable_redraw_for_testing = val; 884 else if (STRCMP(name, (char_u *)"redraw_flag") == 0) 885 ignore_redraw_flag_for_testing = val; 886 else if (STRCMP(name, (char_u *)"char_avail") == 0) 887 disable_char_avail_for_testing = val; 888 else if (STRCMP(name, (char_u *)"starting") == 0) 889 { 890 if (val) 891 { 892 if (save_starting < 0) 893 save_starting = starting; 894 starting = 0; 895 } 896 else 897 { 898 starting = save_starting; 899 save_starting = -1; 900 } 901 } 902 else if (STRCMP(name, (char_u *)"nfa_fail") == 0) 903 nfa_fail_for_testing = val; 904 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0) 905 no_query_mouse_for_testing = val; 906 else if (STRCMP(name, (char_u *)"no_wait_return") == 0) 907 no_wait_return = val; 908 else if (STRCMP(name, (char_u *)"ui_delay") == 0) 909 ui_delay_for_testing = val; 910 else if (STRCMP(name, (char_u *)"term_props") == 0) 911 reset_term_props_on_termresponse = val; 912 else if (STRCMP(name, (char_u *)"ALL") == 0) 913 { 914 disable_char_avail_for_testing = FALSE; 915 disable_redraw_for_testing = FALSE; 916 ignore_redraw_flag_for_testing = FALSE; 917 nfa_fail_for_testing = FALSE; 918 no_query_mouse_for_testing = FALSE; 919 ui_delay_for_testing = 0; 920 reset_term_props_on_termresponse = FALSE; 921 if (save_starting >= 0) 922 { 923 starting = save_starting; 924 save_starting = -1; 925 } 926 } 927 else 928 semsg(_(e_invarg2), name); 929 } 930 } 931 932 /* 933 * "test_refcount({expr})" function 934 */ 935 void 936 f_test_refcount(typval_T *argvars, typval_T *rettv) 937 { 938 int retval = -1; 939 940 switch (argvars[0].v_type) 941 { 942 case VAR_UNKNOWN: 943 case VAR_ANY: 944 case VAR_VOID: 945 case VAR_NUMBER: 946 case VAR_BOOL: 947 case VAR_FLOAT: 948 case VAR_SPECIAL: 949 case VAR_STRING: 950 break; 951 case VAR_JOB: 952 #ifdef FEAT_JOB_CHANNEL 953 if (argvars[0].vval.v_job != NULL) 954 retval = argvars[0].vval.v_job->jv_refcount - 1; 955 #endif 956 break; 957 case VAR_CHANNEL: 958 #ifdef FEAT_JOB_CHANNEL 959 if (argvars[0].vval.v_channel != NULL) 960 retval = argvars[0].vval.v_channel->ch_refcount - 1; 961 #endif 962 break; 963 case VAR_FUNC: 964 if (argvars[0].vval.v_string != NULL) 965 { 966 ufunc_T *fp; 967 968 fp = find_func(argvars[0].vval.v_string, FALSE, NULL); 969 if (fp != NULL) 970 retval = fp->uf_refcount; 971 } 972 break; 973 case VAR_PARTIAL: 974 if (argvars[0].vval.v_partial != NULL) 975 retval = argvars[0].vval.v_partial->pt_refcount - 1; 976 break; 977 case VAR_BLOB: 978 if (argvars[0].vval.v_blob != NULL) 979 retval = argvars[0].vval.v_blob->bv_refcount - 1; 980 break; 981 case VAR_LIST: 982 if (argvars[0].vval.v_list != NULL) 983 retval = argvars[0].vval.v_list->lv_refcount - 1; 984 break; 985 case VAR_DICT: 986 if (argvars[0].vval.v_dict != NULL) 987 retval = argvars[0].vval.v_dict->dv_refcount - 1; 988 break; 989 } 990 991 rettv->v_type = VAR_NUMBER; 992 rettv->vval.v_number = retval; 993 994 } 995 996 /* 997 * "test_garbagecollect_now()" function 998 */ 999 void 1000 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 1001 { 1002 // This is dangerous, any Lists and Dicts used internally may be freed 1003 // while still in use. 1004 garbage_collect(TRUE); 1005 } 1006 1007 /* 1008 * "test_garbagecollect_soon()" function 1009 */ 1010 void 1011 f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 1012 { 1013 may_garbage_collect = TRUE; 1014 } 1015 1016 /* 1017 * "test_ignore_error()" function 1018 */ 1019 void 1020 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED) 1021 { 1022 ignore_error_for_testing(tv_get_string(&argvars[0])); 1023 } 1024 1025 void 1026 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv) 1027 { 1028 rettv->v_type = VAR_BLOB; 1029 rettv->vval.v_blob = NULL; 1030 } 1031 1032 #ifdef FEAT_JOB_CHANNEL 1033 void 1034 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) 1035 { 1036 rettv->v_type = VAR_CHANNEL; 1037 rettv->vval.v_channel = NULL; 1038 } 1039 #endif 1040 1041 void 1042 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) 1043 { 1044 rettv_dict_set(rettv, NULL); 1045 } 1046 1047 #ifdef FEAT_JOB_CHANNEL 1048 void 1049 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) 1050 { 1051 rettv->v_type = VAR_JOB; 1052 rettv->vval.v_job = NULL; 1053 } 1054 #endif 1055 1056 void 1057 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) 1058 { 1059 rettv_list_set(rettv, NULL); 1060 } 1061 1062 void 1063 f_test_null_function(typval_T *argvars UNUSED, typval_T *rettv) 1064 { 1065 rettv->v_type = VAR_FUNC; 1066 rettv->vval.v_string = NULL; 1067 } 1068 1069 void 1070 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) 1071 { 1072 rettv->v_type = VAR_PARTIAL; 1073 rettv->vval.v_partial = NULL; 1074 } 1075 1076 void 1077 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) 1078 { 1079 rettv->v_type = VAR_STRING; 1080 rettv->vval.v_string = NULL; 1081 } 1082 1083 void 1084 f_test_unknown(typval_T *argvars UNUSED, typval_T *rettv) 1085 { 1086 rettv->v_type = VAR_UNKNOWN; 1087 } 1088 1089 void 1090 f_test_void(typval_T *argvars UNUSED, typval_T *rettv) 1091 { 1092 rettv->v_type = VAR_VOID; 1093 } 1094 1095 #ifdef FEAT_GUI 1096 void 1097 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED) 1098 { 1099 char_u *which; 1100 long value; 1101 int dragging; 1102 scrollbar_T *sb = NULL; 1103 1104 if (argvars[0].v_type != VAR_STRING 1105 || (argvars[1].v_type) != VAR_NUMBER 1106 || (argvars[2].v_type) != VAR_NUMBER) 1107 { 1108 emsg(_(e_invarg)); 1109 return; 1110 } 1111 which = tv_get_string(&argvars[0]); 1112 value = tv_get_number(&argvars[1]); 1113 dragging = tv_get_number(&argvars[2]); 1114 1115 if (STRCMP(which, "left") == 0) 1116 sb = &curwin->w_scrollbars[SBAR_LEFT]; 1117 else if (STRCMP(which, "right") == 0) 1118 sb = &curwin->w_scrollbars[SBAR_RIGHT]; 1119 else if (STRCMP(which, "hor") == 0) 1120 sb = &gui.bottom_sbar; 1121 if (sb == NULL) 1122 { 1123 semsg(_(e_invarg2), which); 1124 return; 1125 } 1126 gui_drag_scrollbar(sb, value, dragging); 1127 # ifndef USE_ON_FLY_SCROLL 1128 // need to loop through normal_cmd() to handle the scroll events 1129 exec_normal(FALSE, TRUE, FALSE); 1130 # endif 1131 } 1132 #endif 1133 1134 void 1135 f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED) 1136 { 1137 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1; 1138 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1; 1139 } 1140 1141 void 1142 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) 1143 { 1144 time_for_testing = (time_t)tv_get_number(&argvars[0]); 1145 } 1146 1147 1148 #endif // defined(FEAT_EVAL) 1149