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