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