Home | History | Annotate | Line # | Download | only in test
      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_GE(r, 0);
    169   ASSERT_EQ((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_EQ(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_EQ(length, number_of_written);
    196   FillConsoleOutputAttribute(
    197       tty_out->handle, si->default_attr, length, origin, &number_of_written);
    198   ASSERT_EQ(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_EQ((unsigned int) cs->si.length, length);
    221   ASSERT(ReadConsoleOutputAttribute(
    222          tty_out->handle, cs->attributes, cs->si.length, origin, &length));
    223   ASSERT_EQ((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_PTR_LT(start, end);
    265   ASSERT_LE(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_PTR_NE(handle, INVALID_HANDLE_VALUE);
    364 
    365   ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
    366   ASSERT_GE(ttyout_fd, 0);
    367   ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd));
    368   r = uv_tty_init(uv_default_loop(), tty_out, ttyout_fd, 0); /* Writable. */
    369   ASSERT_OK(r);
    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_EQ(cursor_pos_old.Y - 1, cursor_pos.Y);
    398   ASSERT_EQ(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_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y);
    406   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    416   ASSERT_EQ(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(loop);
    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_EQ(cursor_pos_old.Y + 1, cursor_pos.Y);
    449   ASSERT_EQ(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_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y);
    457   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    467   ASSERT_EQ(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(loop);
    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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    500   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    508   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    518   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    528   ASSERT_EQ(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(loop);
    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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    561   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    569   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    579   ASSERT_EQ(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_EQ(1, cursor_pos.Y);
    589   ASSERT_EQ(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(loop);
    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_EQ(cursor_pos_old.Y + 1, cursor_pos.Y);
    622   ASSERT_EQ(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_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y);
    630   ASSERT_EQ(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_EQ(cursor_pos_old.Y, cursor_pos.Y);
    640   ASSERT_EQ(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(loop);
    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_EQ(cursor_pos_old.Y - 1, cursor_pos.Y);
    673   ASSERT_EQ(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_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y);
    681   ASSERT_EQ(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_EQ(1, cursor_pos.Y);
    691   ASSERT_EQ(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(loop);
    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_EQ(1, cursor_pos.X);
    724   ASSERT_EQ(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_EQ(si.width / 4, cursor_pos.X);
    731   ASSERT_EQ(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_EQ(si.width, cursor_pos.X);
    738   ASSERT_EQ(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(loop);
    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_EQ(1, cursor_pos.X);
    770   ASSERT_EQ(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_EQ(si.width / 2, cursor_pos.X);
    778   ASSERT_EQ(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_EQ(si.width, cursor_pos.X);
    786   ASSERT_EQ(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_EQ(si.width / 2, cursor_pos.X);
    793   ASSERT_EQ(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(loop);
    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(loop);
    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(loop);
    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(loop);
    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_EQ(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_EQ(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_EQ(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_EQ(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_EQ(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_EQ(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_EQ(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(loop);
   1041   return 0;
   1042 }
   1043 
   1044 
   1045 TEST_IMPL(tty_set_style) {
   1046 #if _MSC_VER >= 1920 && _MSC_VER <= 1929
   1047   RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. "
   1048               "See: https://github.com/libuv/libuv/issues/3304");
   1049 #else
   1050 
   1051   uv_tty_t tty_out;
   1052   uv_loop_t* loop;
   1053   COORD cursor_pos;
   1054   char buffer[1024];
   1055   struct captured_screen actual = {0}, expect = {0};
   1056   WORD fg, bg;
   1057   WORD fg_attrs[9][2] = {{F_BLACK, FOREGROUND_BLACK},
   1058                          {F_RED, FOREGROUND_RED},
   1059                          {F_GREEN, FOREGROUND_GREEN},
   1060                          {F_YELLOW, FOREGROUND_YELLOW},
   1061                          {F_BLUE, FOREGROUND_BLUE},
   1062                          {F_MAGENTA, FOREGROUND_MAGENTA},
   1063                          {F_CYAN, FOREGROUND_CYAN},
   1064                          {F_WHITE, FOREGROUND_WHITE},
   1065                          {F_DEFAULT, 0}};
   1066   WORD bg_attrs[9][2] = {{B_DEFAULT, 0},
   1067                          {B_BLACK, BACKGROUND_BLACK},
   1068                          {B_RED, BACKGROUND_RED},
   1069                          {B_GREEN, BACKGROUND_GREEN},
   1070                          {B_YELLOW, BACKGROUND_YELLOW},
   1071                          {B_BLUE, BACKGROUND_BLUE},
   1072                          {B_MAGENTA, BACKGROUND_MAGENTA},
   1073                          {B_CYAN, BACKGROUND_CYAN},
   1074                          {B_WHITE, BACKGROUND_WHITE}};
   1075   WORD attr;
   1076   int i, length;
   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 foreground and background color */
   1125   ASSERT_EQ(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(loop);
   1241   return 0;
   1242 #endif
   1243 }
   1244 
   1245 
   1246 TEST_IMPL(tty_save_restore_cursor_position) {
   1247   uv_tty_t tty_out;
   1248   uv_loop_t* loop;
   1249   COORD cursor_pos, cursor_pos_old;
   1250   char buffer[1024];
   1251   struct screen_info si;
   1252 
   1253   loop = uv_default_loop();
   1254 
   1255   initialize_tty(&tty_out);
   1256   get_screen_info(&tty_out, &si);
   1257 
   1258   cursor_pos_old.X = si.width / 2;
   1259   cursor_pos_old.Y = si.height / 2;
   1260   set_cursor_position(&tty_out, cursor_pos_old);
   1261 
   1262   /* save the cursor position */
   1263   snprintf(buffer, sizeof(buffer), "%ss", CSI);
   1264   write_console(&tty_out, buffer);
   1265 
   1266   cursor_pos.X = si.width / 4;
   1267   cursor_pos.Y = si.height / 4;
   1268   set_cursor_position(&tty_out, cursor_pos);
   1269 
   1270   /* restore the cursor position */
   1271   snprintf(buffer, sizeof(buffer), "%su", CSI);
   1272   write_console(&tty_out, buffer);
   1273   get_cursor_position(&tty_out, &cursor_pos);
   1274   ASSERT_EQ(cursor_pos.X, cursor_pos_old.X);
   1275   ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y);
   1276 
   1277   cursor_pos_old.X = si.width / 2;
   1278   cursor_pos_old.Y = si.height / 2;
   1279   set_cursor_position(&tty_out, cursor_pos_old);
   1280 
   1281   /* save the cursor position */
   1282   snprintf(buffer, sizeof(buffer), "%s7", ESC);
   1283   write_console(&tty_out, buffer);
   1284 
   1285   cursor_pos.X = si.width / 4;
   1286   cursor_pos.Y = si.height / 4;
   1287   set_cursor_position(&tty_out, cursor_pos);
   1288 
   1289   /* restore the cursor position */
   1290   snprintf(buffer, sizeof(buffer), "%s8", ESC);
   1291   write_console(&tty_out, buffer);
   1292   get_cursor_position(&tty_out, &cursor_pos);
   1293   ASSERT_EQ(cursor_pos.X, cursor_pos_old.X);
   1294   ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y);
   1295 
   1296   terminate_tty(&tty_out);
   1297 
   1298   uv_run(loop, UV_RUN_DEFAULT);
   1299 
   1300   MAKE_VALGRIND_HAPPY(loop);
   1301   return 0;
   1302 }
   1303 
   1304 
   1305 TEST_IMPL(tty_full_reset) {
   1306   uv_tty_t tty_out;
   1307   uv_loop_t* loop;
   1308   char buffer[1024];
   1309   struct captured_screen actual = {0}, expect = {0};
   1310   COORD cursor_pos;
   1311   DWORD saved_cursor_size;
   1312   BOOL saved_cursor_visibility;
   1313 
   1314   loop = uv_default_loop();
   1315 
   1316   initialize_tty(&tty_out);
   1317 
   1318   capture_screen(&tty_out, &expect);
   1319   setup_screen(&tty_out);
   1320   cursor_pos.X = expect.si.width;
   1321   cursor_pos.Y = expect.si.height;
   1322   set_cursor_position(&tty_out, cursor_pos);
   1323   snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO);
   1324   saved_cursor_size = get_cursor_size(&tty_out);
   1325   set_cursor_size(&tty_out,
   1326                   saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL
   1327                                                          : CURSOR_SIZE_LARGE);
   1328   saved_cursor_visibility = get_cursor_visibility(&tty_out);
   1329   set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE);
   1330   write_console(&tty_out, buffer);
   1331   snprintf(buffer, sizeof(buffer), "%sc", ESC);
   1332   write_console(&tty_out, buffer);
   1333   capture_screen(&tty_out, &actual);
   1334   ASSERT(compare_screen(&tty_out, &actual, &expect));
   1335   ASSERT_EQ(get_cursor_size(&tty_out), saved_cursor_size);
   1336   ASSERT_EQ(get_cursor_visibility(&tty_out), saved_cursor_visibility);
   1337   ASSERT_OK(actual.si.csbi.srWindow.Top);
   1338 
   1339   terminate_tty(&tty_out);
   1340 
   1341   uv_run(loop, UV_RUN_DEFAULT);
   1342 
   1343   MAKE_VALGRIND_HAPPY(loop);
   1344   return 0;
   1345 }
   1346 
   1347 
   1348 TEST_IMPL(tty_escape_sequence_processing) {
   1349 #if _MSC_VER >= 1920 && _MSC_VER <= 1929
   1350   RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. "
   1351               "See: https://github.com/libuv/libuv/issues/3304");
   1352 #else
   1353   uv_tty_t tty_out;
   1354   uv_loop_t* loop;
   1355   COORD cursor_pos, cursor_pos_old;
   1356   DWORD saved_cursor_size;
   1357   char buffer[1024];
   1358   struct captured_screen actual = {0}, expect = {0};
   1359   int dir;
   1360 
   1361   loop = uv_default_loop();
   1362 
   1363   initialize_tty(&tty_out);
   1364 
   1365   /* CSI + finally 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) + finally 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 + finally 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 + finally 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_EQ(1, cursor_pos.X);
   1524   ASSERT_EQ(1, cursor_pos.Y);
   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_EQ(1, cursor_pos.X);
   1558   ASSERT_EQ(1, cursor_pos.Y);
   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_EQ(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_EQ(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   /* Finally 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(loop);
   1624   return 0;
   1625 #endif
   1626 }
   1627 
   1628 #else
   1629 
   1630 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
   1631 
   1632 #endif  /* ifdef _WIN32 */
   1633