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