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