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