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