1 /* Copyright libuv project contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #ifdef _WIN32 23 24 #include "task.h" 25 #include "uv.h" 26 27 #include <io.h> 28 #include <windows.h> 29 30 #include <errno.h> 31 #include <string.h> 32 33 #define ESC "\033" 34 #define CSI ESC "[" 35 #define ST ESC "\\" 36 #define BEL "\x07" 37 #define HELLO "Hello" 38 39 #define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) 40 #define FOREGROUND_BLACK 0 41 #define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN) 42 #define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE) 43 #define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE) 44 #define BACKGROUND_WHITE (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) 45 #define BACKGROUND_BLACK 0 46 #define BACKGROUND_YELLOW (BACKGROUND_RED | BACKGROUND_GREEN) 47 #define BACKGROUND_CYAN (BACKGROUND_GREEN | BACKGROUND_BLUE) 48 #define BACKGROUND_MAGENTA (BACKGROUND_RED | BACKGROUND_BLUE) 49 50 #define F_INTENSITY 1 51 #define FB_INTENSITY 2 52 #define B_INTENSITY 5 53 #define INVERSE 7 54 #define F_INTENSITY_OFF1 21 55 #define F_INTENSITY_OFF2 22 56 #define B_INTENSITY_OFF 25 57 #define INVERSE_OFF 27 58 #define F_BLACK 30 59 #define F_RED 31 60 #define F_GREEN 32 61 #define F_YELLOW 33 62 #define F_BLUE 34 63 #define F_MAGENTA 35 64 #define F_CYAN 36 65 #define F_WHITE 37 66 #define F_DEFAULT 39 67 #define B_BLACK 40 68 #define B_RED 41 69 #define B_GREEN 42 70 #define B_YELLOW 43 71 #define B_BLUE 44 72 #define B_MAGENTA 45 73 #define B_CYAN 46 74 #define B_WHITE 47 75 #define B_DEFAULT 49 76 77 #define CURSOR_SIZE_SMALL 25 78 #define CURSOR_SIZE_MIDDLE 50 79 #define CURSOR_SIZE_LARGE 100 80 81 struct screen_info { 82 CONSOLE_SCREEN_BUFFER_INFO csbi; 83 int top; 84 int width; 85 int height; 86 int length; 87 WORD default_attr; 88 }; 89 90 struct captured_screen { 91 char* text; 92 WORD* attributes; 93 struct screen_info si; 94 }; 95 96 static void get_screen_info(uv_tty_t* tty_out, struct screen_info* si) { 97 ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &(si->csbi))); 98 si->width = si->csbi.dwSize.X; 99 si->height = si->csbi.srWindow.Bottom - si->csbi.srWindow.Top + 1; 100 si->length = si->width * si->height; 101 si->default_attr = si->csbi.wAttributes; 102 si->top = si->csbi.srWindow.Top; 103 } 104 105 static void set_cursor_position(uv_tty_t* tty_out, COORD pos) { 106 HANDLE handle = tty_out->handle; 107 CONSOLE_SCREEN_BUFFER_INFO info; 108 ASSERT(GetConsoleScreenBufferInfo(handle, &info)); 109 pos.X -= 1; 110 pos.Y += info.srWindow.Top - 1; 111 ASSERT(SetConsoleCursorPosition(handle, pos)); 112 } 113 114 static void get_cursor_position(uv_tty_t* tty_out, COORD* cursor_position) { 115 HANDLE handle = tty_out->handle; 116 CONSOLE_SCREEN_BUFFER_INFO info; 117 ASSERT(GetConsoleScreenBufferInfo(handle, &info)); 118 cursor_position->X = info.dwCursorPosition.X + 1; 119 cursor_position->Y = info.dwCursorPosition.Y - info.srWindow.Top + 1; 120 } 121 122 static void set_cursor_to_home(uv_tty_t* tty_out) { 123 COORD origin = {1, 1}; 124 set_cursor_position(tty_out, origin); 125 } 126 127 static CONSOLE_CURSOR_INFO get_cursor_info(uv_tty_t* tty_out) { 128 HANDLE handle = tty_out->handle; 129 CONSOLE_CURSOR_INFO info; 130 ASSERT(GetConsoleCursorInfo(handle, &info)); 131 return info; 132 } 133 134 static void set_cursor_size(uv_tty_t* tty_out, DWORD size) { 135 CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); 136 info.dwSize = size; 137 ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); 138 } 139 140 static DWORD get_cursor_size(uv_tty_t* tty_out) { 141 return get_cursor_info(tty_out).dwSize; 142 } 143 144 static void set_cursor_visibility(uv_tty_t* tty_out, BOOL visible) { 145 CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); 146 info.bVisible = visible; 147 ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); 148 } 149 150 static BOOL get_cursor_visibility(uv_tty_t* tty_out) { 151 return get_cursor_info(tty_out).bVisible; 152 } 153 154 static BOOL is_scrolling(uv_tty_t* tty_out, struct screen_info si) { 155 CONSOLE_SCREEN_BUFFER_INFO info; 156 ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); 157 return info.srWindow.Top != si.top; 158 } 159 160 static void write_console(uv_tty_t* tty_out, char* src) { 161 int r; 162 uv_buf_t buf; 163 164 buf.base = src; 165 buf.len = strlen(buf.base); 166 167 r = uv_try_write((uv_stream_t*) tty_out, &buf, 1); 168 ASSERT(r >= 0); 169 ASSERT((unsigned int) r == buf.len); 170 } 171 172 static void setup_screen(uv_tty_t* tty_out) { 173 DWORD length, number_of_written; 174 COORD origin; 175 CONSOLE_SCREEN_BUFFER_INFO info; 176 ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); 177 length = info.dwSize.X * (info.srWindow.Bottom - info.srWindow.Top + 1); 178 origin.X = 0; 179 origin.Y = info.srWindow.Top; 180 ASSERT(FillConsoleOutputCharacter( 181 tty_out->handle, '.', length, origin, &number_of_written)); 182 ASSERT(length == number_of_written); 183 } 184 185 static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) { 186 DWORD length, number_of_written; 187 COORD origin; 188 CONSOLE_SCREEN_BUFFER_INFO info; 189 ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); 190 length = (info.srWindow.Bottom - info.srWindow.Top + 1) * info.dwSize.X - 1; 191 origin.X = 0; 192 origin.Y = info.srWindow.Top; 193 FillConsoleOutputCharacterA( 194 tty_out->handle, ' ', length, origin, &number_of_written); 195 ASSERT(length == number_of_written); 196 FillConsoleOutputAttribute( 197 tty_out->handle, si->default_attr, length, origin, &number_of_written); 198 ASSERT(length == number_of_written); 199 } 200 201 static void free_screen(struct captured_screen* cs) { 202 free(cs->text); 203 cs->text = NULL; 204 free(cs->attributes); 205 cs->attributes = NULL; 206 } 207 208 static void capture_screen(uv_tty_t* tty_out, struct captured_screen* cs) { 209 DWORD length; 210 COORD origin; 211 get_screen_info(tty_out, &(cs->si)); 212 origin.X = 0; 213 origin.Y = cs->si.csbi.srWindow.Top; 214 cs->text = malloc(cs->si.length * sizeof(*cs->text)); 215 ASSERT_NOT_NULL(cs->text); 216 cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes)); 217 ASSERT_NOT_NULL(cs->attributes); 218 ASSERT(ReadConsoleOutputCharacter( 219 tty_out->handle, cs->text, cs->si.length, origin, &length)); 220 ASSERT((unsigned int) cs->si.length == length); 221 ASSERT(ReadConsoleOutputAttribute( 222 tty_out->handle, cs->attributes, cs->si.length, origin, &length)); 223 ASSERT((unsigned int) cs->si.length == length); 224 } 225 226 static void make_expect_screen_erase(struct captured_screen* cs, 227 COORD cursor_position, 228 int dir, 229 BOOL entire_screen) { 230 /* beginning of line */ 231 char* start; 232 char* end; 233 start = cs->text + cs->si.width * (cursor_position.Y - 1); 234 if (dir == 0) { 235 if (entire_screen) { 236 /* erase to end of screen */ 237 end = cs->text + cs->si.length; 238 } else { 239 /* erase to end of line */ 240 end = start + cs->si.width; 241 } 242 /* erase from postition of cursor */ 243 start += cursor_position.X - 1; 244 } else if (dir == 1) { 245 /* erase to position of cursor */ 246 end = start + cursor_position.X; 247 if (entire_screen) { 248 /* erase form beginning of screen */ 249 start = cs->text; 250 } 251 } else if (dir == 2) { 252 if (entire_screen) { 253 /* erase form beginning of screen */ 254 start = cs->text; 255 /* erase to end of screen */ 256 end = cs->text + cs->si.length; 257 } else { 258 /* erase to end of line */ 259 end = start + cs->si.width; 260 } 261 } else { 262 ASSERT(FALSE); 263 } 264 ASSERT(start < end); 265 ASSERT(end - cs->text <= cs->si.length); 266 for (; start < end; start++) { 267 *start = ' '; 268 } 269 } 270 271 static void make_expect_screen_write(struct captured_screen* cs, 272 COORD cursor_position, 273 const char* text) { 274 /* position of cursor */ 275 char* start; 276 start = cs->text + cs->si.width * (cursor_position.Y - 1) + 277 cursor_position.X - 1; 278 size_t length = strlen(text); 279 size_t remain_length = cs->si.length - (cs->text - start); 280 length = length > remain_length ? remain_length : length; 281 memcpy(start, text, length); 282 } 283 284 static void make_expect_screen_set_attr(struct captured_screen* cs, 285 COORD cursor_position, 286 size_t length, 287 WORD attr) { 288 WORD* start; 289 start = cs->attributes + cs->si.width * (cursor_position.Y - 1) + 290 cursor_position.X - 1; 291 size_t remain_length = cs->si.length - (cs->attributes - start); 292 length = length > remain_length ? remain_length : length; 293 while (length) { 294 *start = attr; 295 start++; 296 length--; 297 } 298 } 299 300 static BOOL compare_screen(uv_tty_t* tty_out, 301 struct captured_screen* actual, 302 struct captured_screen* expect) { 303 int line, col; 304 BOOL result = TRUE; 305 int current = 0; 306 ASSERT(actual->text); 307 ASSERT(actual->attributes); 308 ASSERT(expect->text); 309 ASSERT(expect->attributes); 310 if (actual->si.length != expect->si.length) { 311 return FALSE; 312 } 313 if (actual->si.width != expect->si.width) { 314 return FALSE; 315 } 316 if (actual->si.height != expect->si.height) { 317 return FALSE; 318 } 319 while (current < actual->si.length) { 320 if (*(actual->text + current) != *(expect->text + current)) { 321 line = current / actual->si.width + 1; 322 col = current - actual->si.width * (line - 1) + 1; 323 fprintf(stderr, 324 "line:%d col:%d expected character '%c' but found '%c'\n", 325 line, 326 col, 327 *(expect->text + current), 328 *(actual->text + current)); 329 result = FALSE; 330 } 331 if (*(actual->attributes + current) != *(expect->attributes + current)) { 332 line = current / actual->si.width + 1; 333 col = current - actual->si.width * (line - 1) + 1; 334 fprintf(stderr, 335 "line:%d col:%d expected attributes '%u' but found '%u'\n", 336 line, 337 col, 338 *(expect->attributes + current), 339 *(actual->attributes + current)); 340 result = FALSE; 341 } 342 current++; 343 } 344 clear_screen(tty_out, &expect->si); 345 free_screen(expect); 346 free_screen(actual); 347 return result; 348 } 349 350 static void initialize_tty(uv_tty_t* tty_out) { 351 int r; 352 int ttyout_fd; 353 /* Make sure we have an FD that refers to a tty */ 354 HANDLE handle; 355 356 uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED); 357 358 handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 359 FILE_SHARE_READ | FILE_SHARE_WRITE, 360 NULL, 361 CONSOLE_TEXTMODE_BUFFER, 362 NULL); 363 ASSERT(handle != INVALID_HANDLE_VALUE); 364 365 ttyout_fd = _open_osfhandle((intptr_t) handle, 0); 366 ASSERT(ttyout_fd >= 0); 367 ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); 368 r = uv_tty_init(uv_default_loop(), tty_out, ttyout_fd, 0); /* Writable. */ 369 ASSERT(r == 0); 370 } 371 372 static void terminate_tty(uv_tty_t* tty_out) { 373 set_cursor_to_home(tty_out); 374 uv_close((uv_handle_t*) tty_out, NULL); 375 } 376 377 TEST_IMPL(tty_cursor_up) { 378 uv_tty_t tty_out; 379 uv_loop_t* loop; 380 COORD cursor_pos, cursor_pos_old; 381 char buffer[1024]; 382 struct screen_info si; 383 384 loop = uv_default_loop(); 385 386 initialize_tty(&tty_out); 387 get_screen_info(&tty_out, &si); 388 389 cursor_pos_old.X = si.width / 2; 390 cursor_pos_old.Y = si.height / 2; 391 set_cursor_position(&tty_out, cursor_pos_old); 392 393 /* cursor up one times if omitted arguments */ 394 snprintf(buffer, sizeof(buffer), "%sA", CSI); 395 write_console(&tty_out, buffer); 396 get_cursor_position(&tty_out, &cursor_pos); 397 ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); 398 ASSERT(cursor_pos_old.X == cursor_pos.X); 399 400 /* cursor up nth times */ 401 cursor_pos_old = cursor_pos; 402 snprintf(buffer, sizeof(buffer), "%s%dA", CSI, si.height / 4); 403 write_console(&tty_out, buffer); 404 get_cursor_position(&tty_out, &cursor_pos); 405 ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); 406 ASSERT(cursor_pos_old.X == cursor_pos.X); 407 408 /* cursor up from Window top does nothing */ 409 cursor_pos_old.X = 1; 410 cursor_pos_old.Y = 1; 411 set_cursor_position(&tty_out, cursor_pos_old); 412 snprintf(buffer, sizeof(buffer), "%sA", CSI); 413 write_console(&tty_out, buffer); 414 get_cursor_position(&tty_out, &cursor_pos); 415 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 416 ASSERT(cursor_pos_old.X == cursor_pos.X); 417 ASSERT(!is_scrolling(&tty_out, si)); 418 419 terminate_tty(&tty_out); 420 421 uv_run(loop, UV_RUN_DEFAULT); 422 423 MAKE_VALGRIND_HAPPY(); 424 return 0; 425 } 426 427 428 TEST_IMPL(tty_cursor_down) { 429 uv_tty_t tty_out; 430 uv_loop_t* loop; 431 COORD cursor_pos, cursor_pos_old; 432 char buffer[1024]; 433 struct screen_info si; 434 435 loop = uv_default_loop(); 436 437 initialize_tty(&tty_out); 438 get_screen_info(&tty_out, &si); 439 440 cursor_pos_old.X = si.width / 2; 441 cursor_pos_old.Y = si.height / 2; 442 set_cursor_position(&tty_out, cursor_pos_old); 443 444 /* cursor down one times if omitted arguments */ 445 snprintf(buffer, sizeof(buffer), "%sB", CSI); 446 write_console(&tty_out, buffer); 447 get_cursor_position(&tty_out, &cursor_pos); 448 ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); 449 ASSERT(cursor_pos_old.X == cursor_pos.X); 450 451 /* cursor down nth times */ 452 cursor_pos_old = cursor_pos; 453 snprintf(buffer, sizeof(buffer), "%s%dB", CSI, si.height / 4); 454 write_console(&tty_out, buffer); 455 get_cursor_position(&tty_out, &cursor_pos); 456 ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); 457 ASSERT(cursor_pos_old.X == cursor_pos.X); 458 459 /* cursor down from bottom line does nothing */ 460 cursor_pos_old.X = si.width / 2; 461 cursor_pos_old.Y = si.height; 462 set_cursor_position(&tty_out, cursor_pos_old); 463 snprintf(buffer, sizeof(buffer), "%sB", CSI); 464 write_console(&tty_out, buffer); 465 get_cursor_position(&tty_out, &cursor_pos); 466 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 467 ASSERT(cursor_pos_old.X == cursor_pos.X); 468 ASSERT(!is_scrolling(&tty_out, si)); 469 470 terminate_tty(&tty_out); 471 472 uv_run(loop, UV_RUN_DEFAULT); 473 474 MAKE_VALGRIND_HAPPY(); 475 return 0; 476 } 477 478 479 TEST_IMPL(tty_cursor_forward) { 480 uv_tty_t tty_out; 481 uv_loop_t* loop; 482 COORD cursor_pos, cursor_pos_old; 483 char buffer[1024]; 484 struct screen_info si; 485 486 loop = uv_default_loop(); 487 488 initialize_tty(&tty_out); 489 get_screen_info(&tty_out, &si); 490 491 cursor_pos_old.X = si.width / 2; 492 cursor_pos_old.Y = si.height / 2; 493 set_cursor_position(&tty_out, cursor_pos_old); 494 495 /* cursor forward one times if omitted arguments */ 496 snprintf(buffer, sizeof(buffer), "%sC", CSI); 497 write_console(&tty_out, buffer); 498 get_cursor_position(&tty_out, &cursor_pos); 499 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 500 ASSERT(cursor_pos_old.X + 1 == cursor_pos.X); 501 502 /* cursor forward nth times */ 503 cursor_pos_old = cursor_pos; 504 snprintf(buffer, sizeof(buffer), "%s%dC", CSI, si.width / 4); 505 write_console(&tty_out, buffer); 506 get_cursor_position(&tty_out, &cursor_pos); 507 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 508 ASSERT(cursor_pos_old.X + si.width / 4 == cursor_pos.X); 509 510 /* cursor forward from end of line does nothing*/ 511 cursor_pos_old.X = si.width; 512 cursor_pos_old.Y = si.height / 2; 513 set_cursor_position(&tty_out, cursor_pos_old); 514 snprintf(buffer, sizeof(buffer), "%sC", CSI); 515 write_console(&tty_out, buffer); 516 get_cursor_position(&tty_out, &cursor_pos); 517 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 518 ASSERT(cursor_pos_old.X == cursor_pos.X); 519 520 /* cursor forward from end of screen does nothing */ 521 cursor_pos_old.X = si.width; 522 cursor_pos_old.Y = si.height; 523 set_cursor_position(&tty_out, cursor_pos_old); 524 snprintf(buffer, sizeof(buffer), "%sC", CSI); 525 write_console(&tty_out, buffer); 526 get_cursor_position(&tty_out, &cursor_pos); 527 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 528 ASSERT(cursor_pos_old.X == cursor_pos.X); 529 ASSERT(!is_scrolling(&tty_out, si)); 530 531 terminate_tty(&tty_out); 532 533 uv_run(loop, UV_RUN_DEFAULT); 534 535 MAKE_VALGRIND_HAPPY(); 536 return 0; 537 } 538 539 540 TEST_IMPL(tty_cursor_back) { 541 uv_tty_t tty_out; 542 uv_loop_t* loop; 543 COORD cursor_pos, cursor_pos_old; 544 char buffer[1024]; 545 struct screen_info si; 546 547 loop = uv_default_loop(); 548 549 initialize_tty(&tty_out); 550 get_screen_info(&tty_out, &si); 551 552 cursor_pos_old.X = si.width / 2; 553 cursor_pos_old.Y = si.height / 2; 554 set_cursor_position(&tty_out, cursor_pos_old); 555 556 /* cursor back one times if omitted arguments */ 557 snprintf(buffer, sizeof(buffer), "%sD", CSI); 558 write_console(&tty_out, buffer); 559 get_cursor_position(&tty_out, &cursor_pos); 560 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 561 ASSERT(cursor_pos_old.X - 1 == cursor_pos.X); 562 563 /* cursor back nth times */ 564 cursor_pos_old = cursor_pos; 565 snprintf(buffer, sizeof(buffer), "%s%dD", CSI, si.width / 4); 566 write_console(&tty_out, buffer); 567 get_cursor_position(&tty_out, &cursor_pos); 568 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 569 ASSERT(cursor_pos_old.X - si.width / 4 == cursor_pos.X); 570 571 /* cursor back from beginning of line does nothing */ 572 cursor_pos_old.X = 1; 573 cursor_pos_old.Y = si.height / 2; 574 set_cursor_position(&tty_out, cursor_pos_old); 575 snprintf(buffer, sizeof(buffer), "%sD", CSI); 576 write_console(&tty_out, buffer); 577 get_cursor_position(&tty_out, &cursor_pos); 578 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 579 ASSERT(cursor_pos_old.X == cursor_pos.X); 580 581 /* cursor back from top of screen does nothing */ 582 cursor_pos_old.X = 1; 583 cursor_pos_old.Y = 1; 584 set_cursor_position(&tty_out, cursor_pos_old); 585 snprintf(buffer, sizeof(buffer), "%sD", CSI); 586 write_console(&tty_out, buffer); 587 get_cursor_position(&tty_out, &cursor_pos); 588 ASSERT(1 == cursor_pos.Y); 589 ASSERT(1 == cursor_pos.X); 590 ASSERT(!is_scrolling(&tty_out, si)); 591 592 terminate_tty(&tty_out); 593 594 uv_run(loop, UV_RUN_DEFAULT); 595 596 MAKE_VALGRIND_HAPPY(); 597 return 0; 598 } 599 600 601 TEST_IMPL(tty_cursor_next_line) { 602 uv_tty_t tty_out; 603 uv_loop_t* loop; 604 COORD cursor_pos, cursor_pos_old; 605 char buffer[1024]; 606 struct screen_info si; 607 608 loop = uv_default_loop(); 609 610 initialize_tty(&tty_out); 611 get_screen_info(&tty_out, &si); 612 613 cursor_pos_old.X = si.width / 2; 614 cursor_pos_old.Y = si.height / 2; 615 set_cursor_position(&tty_out, cursor_pos_old); 616 617 /* cursor next line one times if omitted arguments */ 618 snprintf(buffer, sizeof(buffer), "%sE", CSI); 619 write_console(&tty_out, buffer); 620 get_cursor_position(&tty_out, &cursor_pos); 621 ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); 622 ASSERT(1 == cursor_pos.X); 623 624 /* cursor next line nth times */ 625 cursor_pos_old = cursor_pos; 626 snprintf(buffer, sizeof(buffer), "%s%dE", CSI, si.height / 4); 627 write_console(&tty_out, buffer); 628 get_cursor_position(&tty_out, &cursor_pos); 629 ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); 630 ASSERT(1 == cursor_pos.X); 631 632 /* cursor next line from buttom row moves beginning of line */ 633 cursor_pos_old.X = si.width / 2; 634 cursor_pos_old.Y = si.height; 635 set_cursor_position(&tty_out, cursor_pos_old); 636 snprintf(buffer, sizeof(buffer), "%sE", CSI); 637 write_console(&tty_out, buffer); 638 get_cursor_position(&tty_out, &cursor_pos); 639 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 640 ASSERT(1 == cursor_pos.X); 641 ASSERT(!is_scrolling(&tty_out, si)); 642 643 terminate_tty(&tty_out); 644 645 uv_run(loop, UV_RUN_DEFAULT); 646 647 MAKE_VALGRIND_HAPPY(); 648 return 0; 649 } 650 651 652 TEST_IMPL(tty_cursor_previous_line) { 653 uv_tty_t tty_out; 654 uv_loop_t* loop; 655 COORD cursor_pos, cursor_pos_old; 656 char buffer[1024]; 657 struct screen_info si; 658 659 loop = uv_default_loop(); 660 661 initialize_tty(&tty_out); 662 get_screen_info(&tty_out, &si); 663 664 cursor_pos_old.X = si.width / 2; 665 cursor_pos_old.Y = si.height / 2; 666 set_cursor_position(&tty_out, cursor_pos_old); 667 668 /* cursor previous line one times if omitted arguments */ 669 snprintf(buffer, sizeof(buffer), "%sF", CSI); 670 write_console(&tty_out, buffer); 671 get_cursor_position(&tty_out, &cursor_pos); 672 ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); 673 ASSERT(1 == cursor_pos.X); 674 675 /* cursor previous line nth times */ 676 cursor_pos_old = cursor_pos; 677 snprintf(buffer, sizeof(buffer), "%s%dF", CSI, si.height / 4); 678 write_console(&tty_out, buffer); 679 get_cursor_position(&tty_out, &cursor_pos); 680 ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); 681 ASSERT(1 == cursor_pos.X); 682 683 /* cursor previous line from top of screen does nothing */ 684 cursor_pos_old.X = 1; 685 cursor_pos_old.Y = 1; 686 set_cursor_position(&tty_out, cursor_pos_old); 687 snprintf(buffer, sizeof(buffer), "%sD", CSI); 688 write_console(&tty_out, buffer); 689 get_cursor_position(&tty_out, &cursor_pos); 690 ASSERT(1 == cursor_pos.Y); 691 ASSERT(1 == cursor_pos.X); 692 ASSERT(!is_scrolling(&tty_out, si)); 693 694 terminate_tty(&tty_out); 695 696 uv_run(loop, UV_RUN_DEFAULT); 697 698 MAKE_VALGRIND_HAPPY(); 699 return 0; 700 } 701 702 703 TEST_IMPL(tty_cursor_horizontal_move_absolute) { 704 uv_tty_t tty_out; 705 uv_loop_t* loop; 706 COORD cursor_pos, cursor_pos_old; 707 char buffer[1024]; 708 struct screen_info si; 709 710 loop = uv_default_loop(); 711 712 initialize_tty(&tty_out); 713 get_screen_info(&tty_out, &si); 714 715 cursor_pos_old.X = si.width / 2; 716 cursor_pos_old.Y = si.height / 2; 717 set_cursor_position(&tty_out, cursor_pos_old); 718 719 /* Move to beginning of line if omitted argument */ 720 snprintf(buffer, sizeof(buffer), "%sG", CSI); 721 write_console(&tty_out, buffer); 722 get_cursor_position(&tty_out, &cursor_pos); 723 ASSERT(1 == cursor_pos.X); 724 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 725 726 /* Move cursor to nth character */ 727 snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width / 4); 728 write_console(&tty_out, buffer); 729 get_cursor_position(&tty_out, &cursor_pos); 730 ASSERT(si.width / 4 == cursor_pos.X); 731 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 732 733 /* Moving out of screen will fit within screen */ 734 snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width + 1); 735 write_console(&tty_out, buffer); 736 get_cursor_position(&tty_out, &cursor_pos); 737 ASSERT(si.width == cursor_pos.X); 738 ASSERT(cursor_pos_old.Y == cursor_pos.Y); 739 740 terminate_tty(&tty_out); 741 742 uv_run(loop, UV_RUN_DEFAULT); 743 744 MAKE_VALGRIND_HAPPY(); 745 return 0; 746 } 747 748 749 TEST_IMPL(tty_cursor_move_absolute) { 750 uv_tty_t tty_out; 751 uv_loop_t* loop; 752 COORD cursor_pos; 753 char buffer[1024]; 754 struct screen_info si; 755 756 loop = uv_default_loop(); 757 758 initialize_tty(&tty_out); 759 get_screen_info(&tty_out, &si); 760 761 cursor_pos.X = si.width / 2; 762 cursor_pos.Y = si.height / 2; 763 set_cursor_position(&tty_out, cursor_pos); 764 765 /* Move the cursor to home if omitted arguments */ 766 snprintf(buffer, sizeof(buffer), "%sH", CSI); 767 write_console(&tty_out, buffer); 768 get_cursor_position(&tty_out, &cursor_pos); 769 ASSERT(1 == cursor_pos.X); 770 ASSERT(1 == cursor_pos.Y); 771 772 /* Move the cursor to the middle of the screen */ 773 snprintf( 774 buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width / 2); 775 write_console(&tty_out, buffer); 776 get_cursor_position(&tty_out, &cursor_pos); 777 ASSERT(si.width / 2 == cursor_pos.X); 778 ASSERT(si.height / 2 == cursor_pos.Y); 779 780 /* Moving out of screen will fit within screen */ 781 snprintf( 782 buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width + 1); 783 write_console(&tty_out, buffer); 784 get_cursor_position(&tty_out, &cursor_pos); 785 ASSERT(si.width == cursor_pos.X); 786 ASSERT(si.height / 2 == cursor_pos.Y); 787 788 snprintf( 789 buffer, sizeof(buffer), "%s%d;%df", CSI, si.height + 1, si.width / 2); 790 write_console(&tty_out, buffer); 791 get_cursor_position(&tty_out, &cursor_pos); 792 ASSERT(si.width / 2 == cursor_pos.X); 793 ASSERT(si.height == cursor_pos.Y); 794 ASSERT(!is_scrolling(&tty_out, si)); 795 796 terminate_tty(&tty_out); 797 798 uv_run(loop, UV_RUN_DEFAULT); 799 800 MAKE_VALGRIND_HAPPY(); 801 return 0; 802 } 803 804 805 TEST_IMPL(tty_hide_show_cursor) { 806 uv_tty_t tty_out; 807 uv_loop_t* loop; 808 char buffer[1024]; 809 BOOL saved_cursor_visibility; 810 811 loop = uv_default_loop(); 812 813 initialize_tty(&tty_out); 814 815 saved_cursor_visibility = get_cursor_visibility(&tty_out); 816 817 /* Hide the cursor */ 818 set_cursor_visibility(&tty_out, TRUE); 819 snprintf(buffer, sizeof(buffer), "%s?25l", CSI); 820 write_console(&tty_out, buffer); 821 ASSERT(!get_cursor_visibility(&tty_out)); 822 823 /* Show the cursor */ 824 set_cursor_visibility(&tty_out, FALSE); 825 snprintf(buffer, sizeof(buffer), "%s?25h", CSI); 826 write_console(&tty_out, buffer); 827 ASSERT(get_cursor_visibility(&tty_out)); 828 829 set_cursor_visibility(&tty_out, saved_cursor_visibility); 830 terminate_tty(&tty_out); 831 832 uv_run(loop, UV_RUN_DEFAULT); 833 834 MAKE_VALGRIND_HAPPY(); 835 return 0; 836 } 837 838 839 TEST_IMPL(tty_erase) { 840 int dir; 841 uv_tty_t tty_out; 842 uv_loop_t* loop; 843 COORD cursor_pos; 844 char buffer[1024]; 845 struct captured_screen actual = {0}, expect = {0}; 846 847 loop = uv_default_loop(); 848 849 initialize_tty(&tty_out); 850 851 /* Erase to below if omitted argument */ 852 dir = 0; 853 setup_screen(&tty_out); 854 capture_screen(&tty_out, &expect); 855 cursor_pos.X = expect.si.width / 2; 856 cursor_pos.Y = expect.si.height / 2; 857 make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); 858 859 set_cursor_position(&tty_out, cursor_pos); 860 snprintf(buffer, sizeof(buffer), "%sJ", CSI); 861 write_console(&tty_out, buffer); 862 capture_screen(&tty_out, &actual); 863 864 ASSERT(compare_screen(&tty_out, &actual, &expect)); 865 866 /* Erase to below(dir = 0) */ 867 setup_screen(&tty_out); 868 capture_screen(&tty_out, &expect); 869 make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); 870 871 set_cursor_position(&tty_out, cursor_pos); 872 snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); 873 write_console(&tty_out, buffer); 874 capture_screen(&tty_out, &actual); 875 876 ASSERT(compare_screen(&tty_out, &actual, &expect)); 877 878 /* Erase to above */ 879 dir = 1; 880 setup_screen(&tty_out); 881 capture_screen(&tty_out, &expect); 882 make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); 883 884 set_cursor_position(&tty_out, cursor_pos); 885 snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); 886 write_console(&tty_out, buffer); 887 capture_screen(&tty_out, &actual); 888 889 ASSERT(compare_screen(&tty_out, &actual, &expect)); 890 891 /* Erase All */ 892 dir = 2; 893 setup_screen(&tty_out); 894 capture_screen(&tty_out, &expect); 895 make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); 896 897 set_cursor_position(&tty_out, cursor_pos); 898 snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); 899 write_console(&tty_out, buffer); 900 capture_screen(&tty_out, &actual); 901 902 ASSERT(compare_screen(&tty_out, &actual, &expect)); 903 904 terminate_tty(&tty_out); 905 906 uv_run(loop, UV_RUN_DEFAULT); 907 908 MAKE_VALGRIND_HAPPY(); 909 return 0; 910 } 911 912 913 TEST_IMPL(tty_erase_line) { 914 int dir; 915 uv_tty_t tty_out; 916 uv_loop_t* loop; 917 COORD cursor_pos; 918 char buffer[1024]; 919 struct captured_screen actual = {0}, expect = {0}; 920 921 loop = uv_default_loop(); 922 923 initialize_tty(&tty_out); 924 925 /* Erase to right if omitted arguments */ 926 dir = 0; 927 setup_screen(&tty_out); 928 capture_screen(&tty_out, &expect); 929 cursor_pos.X = expect.si.width / 2; 930 cursor_pos.Y = expect.si.height / 2; 931 make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); 932 933 set_cursor_position(&tty_out, cursor_pos); 934 snprintf(buffer, sizeof(buffer), "%sK", CSI); 935 write_console(&tty_out, buffer); 936 capture_screen(&tty_out, &actual); 937 938 ASSERT(compare_screen(&tty_out, &actual, &expect)); 939 940 /* Erase to right(dir = 0) */ 941 setup_screen(&tty_out); 942 capture_screen(&tty_out, &expect); 943 make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); 944 945 set_cursor_position(&tty_out, cursor_pos); 946 snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); 947 write_console(&tty_out, buffer); 948 capture_screen(&tty_out, &actual); 949 950 ASSERT(compare_screen(&tty_out, &actual, &expect)); 951 952 /* Erase to Left */ 953 dir = 1; 954 setup_screen(&tty_out); 955 capture_screen(&tty_out, &expect); 956 make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); 957 958 set_cursor_position(&tty_out, cursor_pos); 959 snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); 960 write_console(&tty_out, buffer); 961 capture_screen(&tty_out, &actual); 962 963 ASSERT(compare_screen(&tty_out, &actual, &expect)); 964 965 /* Erase All */ 966 dir = 2; 967 setup_screen(&tty_out); 968 capture_screen(&tty_out, &expect); 969 make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); 970 971 set_cursor_position(&tty_out, cursor_pos); 972 snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); 973 write_console(&tty_out, buffer); 974 capture_screen(&tty_out, &actual); 975 976 ASSERT(compare_screen(&tty_out, &actual, &expect)); 977 978 terminate_tty(&tty_out); 979 980 uv_run(loop, UV_RUN_DEFAULT); 981 982 MAKE_VALGRIND_HAPPY(); 983 return 0; 984 } 985 986 987 TEST_IMPL(tty_set_cursor_shape) { 988 uv_tty_t tty_out; 989 uv_loop_t* loop; 990 DWORD saved_cursor_size; 991 char buffer[1024]; 992 993 loop = uv_default_loop(); 994 995 initialize_tty(&tty_out); 996 997 saved_cursor_size = get_cursor_size(&tty_out); 998 999 /* cursor size large if omitted arguments */ 1000 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1001 snprintf(buffer, sizeof(buffer), "%s q", CSI); 1002 write_console(&tty_out, buffer); 1003 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); 1004 1005 /* cursor size large */ 1006 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1007 snprintf(buffer, sizeof(buffer), "%s1 q", CSI); 1008 write_console(&tty_out, buffer); 1009 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); 1010 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1011 snprintf(buffer, sizeof(buffer), "%s2 q", CSI); 1012 write_console(&tty_out, buffer); 1013 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); 1014 1015 /* cursor size small */ 1016 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1017 snprintf(buffer, sizeof(buffer), "%s3 q", CSI); 1018 write_console(&tty_out, buffer); 1019 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); 1020 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1021 snprintf(buffer, sizeof(buffer), "%s6 q", CSI); 1022 write_console(&tty_out, buffer); 1023 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); 1024 1025 /* Nothing occurs with arguments outside valid range */ 1026 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1027 snprintf(buffer, sizeof(buffer), "%s7 q", CSI); 1028 write_console(&tty_out, buffer); 1029 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); 1030 1031 /* restore cursor size if arguments is zero */ 1032 snprintf(buffer, sizeof(buffer), "%s0 q", CSI); 1033 write_console(&tty_out, buffer); 1034 ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); 1035 1036 terminate_tty(&tty_out); 1037 1038 uv_run(loop, UV_RUN_DEFAULT); 1039 1040 MAKE_VALGRIND_HAPPY(); 1041 return 0; 1042 } 1043 1044 1045 TEST_IMPL(tty_set_style) { 1046 uv_tty_t tty_out; 1047 uv_loop_t* loop; 1048 COORD cursor_pos; 1049 char buffer[1024]; 1050 struct captured_screen actual = {0}, expect = {0}; 1051 WORD fg, bg; 1052 WORD fg_attrs[9][2] = {{F_BLACK, FOREGROUND_BLACK}, 1053 {F_RED, FOREGROUND_RED}, 1054 {F_GREEN, FOREGROUND_GREEN}, 1055 {F_YELLOW, FOREGROUND_YELLOW}, 1056 {F_BLUE, FOREGROUND_BLUE}, 1057 {F_MAGENTA, FOREGROUND_MAGENTA}, 1058 {F_CYAN, FOREGROUND_CYAN}, 1059 {F_WHITE, FOREGROUND_WHITE}, 1060 {F_DEFAULT, 0}}; 1061 WORD bg_attrs[9][2] = {{B_DEFAULT, 0}, 1062 {B_BLACK, BACKGROUND_BLACK}, 1063 {B_RED, BACKGROUND_RED}, 1064 {B_GREEN, BACKGROUND_GREEN}, 1065 {B_YELLOW, BACKGROUND_YELLOW}, 1066 {B_BLUE, BACKGROUND_BLUE}, 1067 {B_MAGENTA, BACKGROUND_MAGENTA}, 1068 {B_CYAN, BACKGROUND_CYAN}, 1069 {B_WHITE, BACKGROUND_WHITE}}; 1070 WORD attr; 1071 int i, length; 1072 1073 #if _MSC_VER >= 1920 && _MSC_VER <= 1929 1074 RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " 1075 "See: https://github.com/libuv/libuv/issues/3304"); 1076 #endif 1077 1078 loop = uv_default_loop(); 1079 1080 initialize_tty(&tty_out); 1081 1082 capture_screen(&tty_out, &expect); 1083 fg_attrs[8][1] = expect.si.default_attr & FOREGROUND_WHITE; 1084 bg_attrs[0][1] = expect.si.default_attr & BACKGROUND_WHITE; 1085 1086 /* Set foreground color */ 1087 length = ARRAY_SIZE(fg_attrs); 1088 for (i = 0; i < length; i++) { 1089 capture_screen(&tty_out, &expect); 1090 cursor_pos.X = expect.si.width / 2; 1091 cursor_pos.Y = expect.si.height / 2; 1092 attr = (expect.si.default_attr & ~FOREGROUND_WHITE) | fg_attrs[i][1]; 1093 make_expect_screen_write(&expect, cursor_pos, HELLO); 1094 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1095 1096 set_cursor_position(&tty_out, cursor_pos); 1097 snprintf( 1098 buffer, sizeof(buffer), "%s%dm%s%sm", CSI, fg_attrs[i][0], HELLO, CSI); 1099 write_console(&tty_out, buffer); 1100 capture_screen(&tty_out, &actual); 1101 1102 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1103 } 1104 1105 /* Set background color */ 1106 length = ARRAY_SIZE(bg_attrs); 1107 for (i = 0; i < length; i++) { 1108 capture_screen(&tty_out, &expect); 1109 cursor_pos.X = expect.si.width / 2; 1110 cursor_pos.Y = expect.si.height / 2; 1111 attr = (expect.si.default_attr & ~BACKGROUND_WHITE) | bg_attrs[i][1]; 1112 make_expect_screen_write(&expect, cursor_pos, HELLO); 1113 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1114 1115 set_cursor_position(&tty_out, cursor_pos); 1116 snprintf( 1117 buffer, sizeof(buffer), "%s%dm%s%sm", CSI, bg_attrs[i][0], HELLO, CSI); 1118 write_console(&tty_out, buffer); 1119 capture_screen(&tty_out, &actual); 1120 1121 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1122 } 1123 1124 /* Set foregroud and background color */ 1125 ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs)); 1126 length = ARRAY_SIZE(bg_attrs); 1127 for (i = 0; i < length; i++) { 1128 capture_screen(&tty_out, &expect); 1129 cursor_pos.X = expect.si.width / 2; 1130 cursor_pos.Y = expect.si.height / 2; 1131 attr = expect.si.default_attr & ~FOREGROUND_WHITE & ~BACKGROUND_WHITE; 1132 attr |= fg_attrs[i][1] | bg_attrs[i][1]; 1133 make_expect_screen_write(&expect, cursor_pos, HELLO); 1134 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1135 1136 set_cursor_position(&tty_out, cursor_pos); 1137 snprintf(buffer, 1138 sizeof(buffer), 1139 "%s%d;%dm%s%sm", 1140 CSI, 1141 bg_attrs[i][0], 1142 fg_attrs[i][0], 1143 HELLO, 1144 CSI); 1145 write_console(&tty_out, buffer); 1146 capture_screen(&tty_out, &actual); 1147 1148 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1149 } 1150 1151 /* Set foreground bright on */ 1152 capture_screen(&tty_out, &expect); 1153 cursor_pos.X = expect.si.width / 2; 1154 cursor_pos.Y = expect.si.height / 2; 1155 set_cursor_position(&tty_out, cursor_pos); 1156 attr = expect.si.default_attr; 1157 attr |= FOREGROUND_INTENSITY; 1158 make_expect_screen_write(&expect, cursor_pos, HELLO); 1159 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1160 cursor_pos.X += strlen(HELLO); 1161 make_expect_screen_write(&expect, cursor_pos, HELLO); 1162 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1163 1164 snprintf(buffer, 1165 sizeof(buffer), 1166 "%s%dm%s%s%dm%s%dm%s%s%dm", 1167 CSI, 1168 F_INTENSITY, 1169 HELLO, 1170 CSI, 1171 F_INTENSITY_OFF1, 1172 CSI, 1173 F_INTENSITY, 1174 HELLO, 1175 CSI, 1176 F_INTENSITY_OFF2); 1177 write_console(&tty_out, buffer); 1178 capture_screen(&tty_out, &actual); 1179 1180 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1181 1182 /* Set background bright on */ 1183 capture_screen(&tty_out, &expect); 1184 cursor_pos.X = expect.si.width / 2; 1185 cursor_pos.Y = expect.si.height / 2; 1186 set_cursor_position(&tty_out, cursor_pos); 1187 attr = expect.si.default_attr; 1188 attr |= BACKGROUND_INTENSITY; 1189 make_expect_screen_write(&expect, cursor_pos, HELLO); 1190 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1191 1192 snprintf(buffer, 1193 sizeof(buffer), 1194 "%s%dm%s%s%dm", 1195 CSI, 1196 B_INTENSITY, 1197 HELLO, 1198 CSI, 1199 B_INTENSITY_OFF); 1200 write_console(&tty_out, buffer); 1201 capture_screen(&tty_out, &actual); 1202 1203 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1204 1205 /* Inverse */ 1206 capture_screen(&tty_out, &expect); 1207 cursor_pos.X = expect.si.width / 2; 1208 cursor_pos.Y = expect.si.height / 2; 1209 set_cursor_position(&tty_out, cursor_pos); 1210 attr = expect.si.default_attr; 1211 fg = attr & FOREGROUND_WHITE; 1212 bg = attr & BACKGROUND_WHITE; 1213 attr &= (~FOREGROUND_WHITE & ~BACKGROUND_WHITE); 1214 attr |= COMMON_LVB_REVERSE_VIDEO; 1215 attr |= fg << 4; 1216 attr |= bg >> 4; 1217 make_expect_screen_write(&expect, cursor_pos, HELLO); 1218 make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); 1219 cursor_pos.X += strlen(HELLO); 1220 make_expect_screen_write(&expect, cursor_pos, HELLO); 1221 1222 snprintf(buffer, 1223 sizeof(buffer), 1224 "%s%dm%s%s%dm%s", 1225 CSI, 1226 INVERSE, 1227 HELLO, 1228 CSI, 1229 INVERSE_OFF, 1230 HELLO); 1231 write_console(&tty_out, buffer); 1232 capture_screen(&tty_out, &actual); 1233 1234 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1235 1236 terminate_tty(&tty_out); 1237 1238 uv_run(loop, UV_RUN_DEFAULT); 1239 1240 MAKE_VALGRIND_HAPPY(); 1241 return 0; 1242 } 1243 1244 1245 TEST_IMPL(tty_save_restore_cursor_position) { 1246 uv_tty_t tty_out; 1247 uv_loop_t* loop; 1248 COORD cursor_pos, cursor_pos_old; 1249 char buffer[1024]; 1250 struct screen_info si; 1251 1252 loop = uv_default_loop(); 1253 1254 initialize_tty(&tty_out); 1255 get_screen_info(&tty_out, &si); 1256 1257 cursor_pos_old.X = si.width / 2; 1258 cursor_pos_old.Y = si.height / 2; 1259 set_cursor_position(&tty_out, cursor_pos_old); 1260 1261 /* save the cursor position */ 1262 snprintf(buffer, sizeof(buffer), "%ss", CSI); 1263 write_console(&tty_out, buffer); 1264 1265 cursor_pos.X = si.width / 4; 1266 cursor_pos.Y = si.height / 4; 1267 set_cursor_position(&tty_out, cursor_pos); 1268 1269 /* restore the cursor position */ 1270 snprintf(buffer, sizeof(buffer), "%su", CSI); 1271 write_console(&tty_out, buffer); 1272 get_cursor_position(&tty_out, &cursor_pos); 1273 ASSERT(cursor_pos.X == cursor_pos_old.X); 1274 ASSERT(cursor_pos.Y == cursor_pos_old.Y); 1275 1276 cursor_pos_old.X = si.width / 2; 1277 cursor_pos_old.Y = si.height / 2; 1278 set_cursor_position(&tty_out, cursor_pos_old); 1279 1280 /* save the cursor position */ 1281 snprintf(buffer, sizeof(buffer), "%s7", ESC); 1282 write_console(&tty_out, buffer); 1283 1284 cursor_pos.X = si.width / 4; 1285 cursor_pos.Y = si.height / 4; 1286 set_cursor_position(&tty_out, cursor_pos); 1287 1288 /* restore the cursor position */ 1289 snprintf(buffer, sizeof(buffer), "%s8", ESC); 1290 write_console(&tty_out, buffer); 1291 get_cursor_position(&tty_out, &cursor_pos); 1292 ASSERT(cursor_pos.X == cursor_pos_old.X); 1293 ASSERT(cursor_pos.Y == cursor_pos_old.Y); 1294 1295 terminate_tty(&tty_out); 1296 1297 uv_run(loop, UV_RUN_DEFAULT); 1298 1299 MAKE_VALGRIND_HAPPY(); 1300 return 0; 1301 } 1302 1303 1304 TEST_IMPL(tty_full_reset) { 1305 uv_tty_t tty_out; 1306 uv_loop_t* loop; 1307 char buffer[1024]; 1308 struct captured_screen actual = {0}, expect = {0}; 1309 COORD cursor_pos; 1310 DWORD saved_cursor_size; 1311 BOOL saved_cursor_visibility; 1312 1313 loop = uv_default_loop(); 1314 1315 initialize_tty(&tty_out); 1316 1317 capture_screen(&tty_out, &expect); 1318 setup_screen(&tty_out); 1319 cursor_pos.X = expect.si.width; 1320 cursor_pos.Y = expect.si.height; 1321 set_cursor_position(&tty_out, cursor_pos); 1322 snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO); 1323 saved_cursor_size = get_cursor_size(&tty_out); 1324 set_cursor_size(&tty_out, 1325 saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL 1326 : CURSOR_SIZE_LARGE); 1327 saved_cursor_visibility = get_cursor_visibility(&tty_out); 1328 set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE); 1329 write_console(&tty_out, buffer); 1330 snprintf(buffer, sizeof(buffer), "%sc", ESC); 1331 write_console(&tty_out, buffer); 1332 capture_screen(&tty_out, &actual); 1333 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1334 ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); 1335 ASSERT(get_cursor_visibility(&tty_out) == saved_cursor_visibility); 1336 ASSERT(actual.si.csbi.srWindow.Top == 0); 1337 1338 terminate_tty(&tty_out); 1339 1340 uv_run(loop, UV_RUN_DEFAULT); 1341 1342 MAKE_VALGRIND_HAPPY(); 1343 return 0; 1344 } 1345 1346 1347 TEST_IMPL(tty_escape_sequence_processing) { 1348 uv_tty_t tty_out; 1349 uv_loop_t* loop; 1350 COORD cursor_pos, cursor_pos_old; 1351 DWORD saved_cursor_size; 1352 char buffer[1024]; 1353 struct captured_screen actual = {0}, expect = {0}; 1354 int dir; 1355 1356 #if _MSC_VER >= 1920 && _MSC_VER <= 1929 1357 RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " 1358 "See: https://github.com/libuv/libuv/issues/3304"); 1359 #endif 1360 1361 loop = uv_default_loop(); 1362 1363 initialize_tty(&tty_out); 1364 1365 /* CSI + finaly byte does not output anything */ 1366 cursor_pos.X = 1; 1367 cursor_pos.Y = 1; 1368 set_cursor_position(&tty_out, cursor_pos); 1369 capture_screen(&tty_out, &expect); 1370 make_expect_screen_write(&expect, cursor_pos, HELLO); 1371 cursor_pos.X += strlen(HELLO); 1372 make_expect_screen_write(&expect, cursor_pos, HELLO); 1373 snprintf(buffer, sizeof(buffer), "%s@%s%s~%s", CSI, HELLO, CSI, HELLO); 1374 write_console(&tty_out, buffer); 1375 capture_screen(&tty_out, &actual); 1376 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1377 1378 /* CSI(C1) + finaly byte does not output anything */ 1379 cursor_pos.X = 1; 1380 cursor_pos.Y = 1; 1381 set_cursor_position(&tty_out, cursor_pos); 1382 capture_screen(&tty_out, &expect); 1383 make_expect_screen_write(&expect, cursor_pos, HELLO); 1384 cursor_pos.X += strlen(HELLO); 1385 make_expect_screen_write(&expect, cursor_pos, HELLO); 1386 snprintf(buffer, sizeof(buffer), "\xC2\x9B@%s\xC2\x9B~%s", HELLO, HELLO); 1387 write_console(&tty_out, buffer); 1388 capture_screen(&tty_out, &actual); 1389 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1390 1391 /* CSI + intermediate byte + finaly byte does not output anything */ 1392 cursor_pos.X = 1; 1393 cursor_pos.Y = 1; 1394 set_cursor_position(&tty_out, cursor_pos); 1395 capture_screen(&tty_out, &expect); 1396 make_expect_screen_write(&expect, cursor_pos, HELLO); 1397 cursor_pos.X += strlen(HELLO); 1398 make_expect_screen_write(&expect, cursor_pos, HELLO); 1399 snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); 1400 write_console(&tty_out, buffer); 1401 capture_screen(&tty_out, &actual); 1402 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1403 1404 /* CSI + parameter byte + finaly byte does not output anything */ 1405 cursor_pos.X = 1; 1406 cursor_pos.Y = 1; 1407 set_cursor_position(&tty_out, cursor_pos); 1408 capture_screen(&tty_out, &expect); 1409 snprintf(buffer, 1410 sizeof(buffer), 1411 "%s0@%s%s>~%s%s?~%s", 1412 CSI, 1413 HELLO, 1414 CSI, 1415 HELLO, 1416 CSI, 1417 HELLO); 1418 make_expect_screen_write(&expect, cursor_pos, HELLO); 1419 cursor_pos.X += strlen(HELLO); 1420 make_expect_screen_write(&expect, cursor_pos, HELLO); 1421 cursor_pos.X += strlen(HELLO); 1422 make_expect_screen_write(&expect, cursor_pos, HELLO); 1423 write_console(&tty_out, buffer); 1424 capture_screen(&tty_out, &actual); 1425 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1426 1427 /* ESC Single-char control does not output anyghing */ 1428 cursor_pos.X = 1; 1429 cursor_pos.Y = 1; 1430 set_cursor_position(&tty_out, cursor_pos); 1431 capture_screen(&tty_out, &expect); 1432 make_expect_screen_write(&expect, cursor_pos, HELLO); 1433 cursor_pos.X += strlen(HELLO); 1434 make_expect_screen_write(&expect, cursor_pos, HELLO); 1435 snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); 1436 write_console(&tty_out, buffer); 1437 capture_screen(&tty_out, &actual); 1438 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1439 1440 /* Nothing is output from ESC + ^, _, P, ] to BEL or ESC \ */ 1441 /* Operaging System Command */ 1442 cursor_pos.X = 1; 1443 cursor_pos.Y = 1; 1444 set_cursor_position(&tty_out, cursor_pos); 1445 capture_screen(&tty_out, &expect); 1446 make_expect_screen_write(&expect, cursor_pos, HELLO); 1447 snprintf(buffer, sizeof(buffer), "%s]0;%s%s%s", ESC, HELLO, BEL, HELLO); 1448 write_console(&tty_out, buffer); 1449 capture_screen(&tty_out, &actual); 1450 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1451 /* Device Control Sequence */ 1452 cursor_pos.X = 1; 1453 cursor_pos.Y = 1; 1454 set_cursor_position(&tty_out, cursor_pos); 1455 capture_screen(&tty_out, &expect); 1456 make_expect_screen_write(&expect, cursor_pos, HELLO); 1457 snprintf(buffer, sizeof(buffer), "%sP$m%s%s", ESC, ST, HELLO); 1458 write_console(&tty_out, buffer); 1459 capture_screen(&tty_out, &actual); 1460 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1461 /* Privacy Message */ 1462 cursor_pos.X = 1; 1463 cursor_pos.Y = 1; 1464 set_cursor_position(&tty_out, cursor_pos); 1465 capture_screen(&tty_out, &expect); 1466 make_expect_screen_write(&expect, cursor_pos, HELLO); 1467 snprintf(buffer, 1468 sizeof(buffer), 1469 "%s^\"%s\\\"%s\"%s%s", 1470 ESC, 1471 HELLO, 1472 HELLO, 1473 ST, 1474 HELLO); 1475 write_console(&tty_out, buffer); 1476 capture_screen(&tty_out, &actual); 1477 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1478 /* Application Program Command */ 1479 cursor_pos.X = 1; 1480 cursor_pos.Y = 1; 1481 set_cursor_position(&tty_out, cursor_pos); 1482 capture_screen(&tty_out, &expect); 1483 make_expect_screen_write(&expect, cursor_pos, HELLO); 1484 snprintf(buffer, 1485 sizeof(buffer), 1486 "%s_\"%s%s%s\"%s%s", 1487 ESC, 1488 HELLO, 1489 ST, 1490 HELLO, 1491 BEL, 1492 HELLO); 1493 write_console(&tty_out, buffer); 1494 capture_screen(&tty_out, &actual); 1495 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1496 1497 /* Ignore double escape */ 1498 cursor_pos.X = 1; 1499 cursor_pos.Y = 1; 1500 set_cursor_position(&tty_out, cursor_pos); 1501 capture_screen(&tty_out, &expect); 1502 make_expect_screen_write(&expect, cursor_pos, HELLO); 1503 cursor_pos.X += strlen(HELLO); 1504 make_expect_screen_write(&expect, cursor_pos, HELLO); 1505 snprintf(buffer, 1506 sizeof(buffer), 1507 "%s%s@%s%s%s~%s", 1508 ESC, 1509 CSI, 1510 HELLO, 1511 ESC, 1512 CSI, 1513 HELLO); 1514 write_console(&tty_out, buffer); 1515 capture_screen(&tty_out, &actual); 1516 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1517 1518 /* Ignored if argument overflow */ 1519 set_cursor_to_home(&tty_out); 1520 snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1); 1521 write_console(&tty_out, buffer); 1522 get_cursor_position(&tty_out, &cursor_pos); 1523 ASSERT(cursor_pos.X == 1); 1524 ASSERT(cursor_pos.Y == 1); 1525 1526 /* Too many argument are ignored */ 1527 cursor_pos.X = 1; 1528 cursor_pos.Y = 1; 1529 set_cursor_position(&tty_out, cursor_pos); 1530 capture_screen(&tty_out, &expect); 1531 make_expect_screen_write(&expect, cursor_pos, HELLO); 1532 snprintf(buffer, 1533 sizeof(buffer), 1534 "%s%d;%d;%d;%d;%dm%s%sm", 1535 CSI, 1536 F_RED, 1537 F_INTENSITY, 1538 INVERSE, 1539 B_CYAN, 1540 B_INTENSITY_OFF, 1541 HELLO, 1542 CSI); 1543 write_console(&tty_out, buffer); 1544 capture_screen(&tty_out, &actual); 1545 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1546 1547 /* In the case of DECSCUSR, the others are ignored */ 1548 set_cursor_to_home(&tty_out); 1549 snprintf(buffer, 1550 sizeof(buffer), 1551 "%s%d;%d H", 1552 CSI, 1553 expect.si.height / 2, 1554 expect.si.width / 2); 1555 write_console(&tty_out, buffer); 1556 get_cursor_position(&tty_out, &cursor_pos); 1557 ASSERT(cursor_pos.X == 1); 1558 ASSERT(cursor_pos.Y == 1); 1559 1560 /* Invalid sequence are ignored */ 1561 saved_cursor_size = get_cursor_size(&tty_out); 1562 set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); 1563 snprintf(buffer, sizeof(buffer), "%s 1q", CSI); 1564 write_console(&tty_out, buffer); 1565 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); 1566 snprintf(buffer, sizeof(buffer), "%s 1 q", CSI); 1567 write_console(&tty_out, buffer); 1568 ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); 1569 set_cursor_size(&tty_out, saved_cursor_size); 1570 1571 /* #1874 2. */ 1572 snprintf(buffer, sizeof(buffer), "%s??25l", CSI); 1573 write_console(&tty_out, buffer); 1574 ASSERT(get_cursor_visibility(&tty_out)); 1575 snprintf(buffer, sizeof(buffer), "%s25?l", CSI); 1576 write_console(&tty_out, buffer); 1577 ASSERT(get_cursor_visibility(&tty_out)); 1578 cursor_pos_old.X = expect.si.width / 2; 1579 cursor_pos_old.Y = expect.si.height / 2; 1580 set_cursor_position(&tty_out, cursor_pos_old); 1581 snprintf(buffer, 1582 sizeof(buffer), 1583 "%s??%d;%df", 1584 CSI, 1585 expect.si.height / 4, 1586 expect.si.width / 4); 1587 write_console(&tty_out, buffer); 1588 get_cursor_position(&tty_out, &cursor_pos); 1589 ASSERT(cursor_pos.X = cursor_pos_old.X); 1590 ASSERT(cursor_pos.Y = cursor_pos_old.Y); 1591 set_cursor_to_home(&tty_out); 1592 1593 /* CSI 25 l does nothing (#1874 4.) */ 1594 snprintf(buffer, sizeof(buffer), "%s25l", CSI); 1595 write_console(&tty_out, buffer); 1596 ASSERT(get_cursor_visibility(&tty_out)); 1597 1598 /* Unsupported sequences are ignored(#1874 5.) */ 1599 dir = 2; 1600 setup_screen(&tty_out); 1601 capture_screen(&tty_out, &expect); 1602 set_cursor_position(&tty_out, cursor_pos); 1603 snprintf(buffer, sizeof(buffer), "%s?%dJ", CSI, dir); 1604 write_console(&tty_out, buffer); 1605 capture_screen(&tty_out, &actual); 1606 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1607 1608 /* Finaly byte immedately after CSI [ are also output(#1874 1.) */ 1609 cursor_pos.X = expect.si.width / 2; 1610 cursor_pos.Y = expect.si.height / 2; 1611 set_cursor_position(&tty_out, cursor_pos); 1612 capture_screen(&tty_out, &expect); 1613 make_expect_screen_write(&expect, cursor_pos, HELLO); 1614 snprintf(buffer, sizeof(buffer), "%s[%s", CSI, HELLO); 1615 write_console(&tty_out, buffer); 1616 capture_screen(&tty_out, &actual); 1617 ASSERT(compare_screen(&tty_out, &actual, &expect)); 1618 1619 terminate_tty(&tty_out); 1620 1621 uv_run(loop, UV_RUN_DEFAULT); 1622 1623 MAKE_VALGRIND_HAPPY(); 1624 return 0; 1625 } 1626 1627 #else 1628 1629 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ 1630 1631 #endif /* ifdef _WIN32 */ 1632