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