xref: /netbsd-src/external/mit/libuv/dist/test/test-tty-escape-sequence-processing.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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(cs->text != NULL);
216   cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes));
217   ASSERT(cs->attributes != NULL);
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   /* postion 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   loop = uv_default_loop();
1074 
1075   initialize_tty(&tty_out);
1076 
1077   capture_screen(&tty_out, &expect);
1078   fg_attrs[8][1] = expect.si.default_attr & FOREGROUND_WHITE;
1079   bg_attrs[0][1] = expect.si.default_attr & BACKGROUND_WHITE;
1080 
1081   /* Set foreground color */
1082   length = ARRAY_SIZE(fg_attrs);
1083   for (i = 0; i < length; i++) {
1084     capture_screen(&tty_out, &expect);
1085     cursor_pos.X = expect.si.width / 2;
1086     cursor_pos.Y = expect.si.height / 2;
1087     attr = (expect.si.default_attr & ~FOREGROUND_WHITE) | fg_attrs[i][1];
1088     make_expect_screen_write(&expect, cursor_pos, HELLO);
1089     make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1090 
1091     set_cursor_position(&tty_out, cursor_pos);
1092     snprintf(
1093         buffer, sizeof(buffer), "%s%dm%s%sm", CSI, fg_attrs[i][0], HELLO, CSI);
1094     write_console(&tty_out, buffer);
1095     capture_screen(&tty_out, &actual);
1096 
1097     ASSERT(compare_screen(&tty_out, &actual, &expect));
1098   }
1099 
1100   /* Set background color */
1101   length = ARRAY_SIZE(bg_attrs);
1102   for (i = 0; i < length; i++) {
1103     capture_screen(&tty_out, &expect);
1104     cursor_pos.X = expect.si.width / 2;
1105     cursor_pos.Y = expect.si.height / 2;
1106     attr = (expect.si.default_attr & ~BACKGROUND_WHITE) | bg_attrs[i][1];
1107     make_expect_screen_write(&expect, cursor_pos, HELLO);
1108     make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1109 
1110     set_cursor_position(&tty_out, cursor_pos);
1111     snprintf(
1112         buffer, sizeof(buffer), "%s%dm%s%sm", CSI, bg_attrs[i][0], HELLO, CSI);
1113     write_console(&tty_out, buffer);
1114     capture_screen(&tty_out, &actual);
1115 
1116     ASSERT(compare_screen(&tty_out, &actual, &expect));
1117   }
1118 
1119   /* Set foregroud and background color */
1120   ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs));
1121   length = ARRAY_SIZE(bg_attrs);
1122   for (i = 0; i < length; i++) {
1123     capture_screen(&tty_out, &expect);
1124     cursor_pos.X = expect.si.width / 2;
1125     cursor_pos.Y = expect.si.height / 2;
1126     attr = expect.si.default_attr & ~FOREGROUND_WHITE & ~BACKGROUND_WHITE;
1127     attr |= fg_attrs[i][1] | bg_attrs[i][1];
1128     make_expect_screen_write(&expect, cursor_pos, HELLO);
1129     make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1130 
1131     set_cursor_position(&tty_out, cursor_pos);
1132     snprintf(buffer,
1133              sizeof(buffer),
1134              "%s%d;%dm%s%sm",
1135              CSI,
1136              bg_attrs[i][0],
1137              fg_attrs[i][0],
1138              HELLO,
1139              CSI);
1140     write_console(&tty_out, buffer);
1141     capture_screen(&tty_out, &actual);
1142 
1143     ASSERT(compare_screen(&tty_out, &actual, &expect));
1144   }
1145 
1146   /* Set foreground bright on */
1147   capture_screen(&tty_out, &expect);
1148   cursor_pos.X = expect.si.width / 2;
1149   cursor_pos.Y = expect.si.height / 2;
1150   set_cursor_position(&tty_out, cursor_pos);
1151   attr = expect.si.default_attr;
1152   attr |= FOREGROUND_INTENSITY;
1153   make_expect_screen_write(&expect, cursor_pos, HELLO);
1154   make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1155   cursor_pos.X += strlen(HELLO);
1156   make_expect_screen_write(&expect, cursor_pos, HELLO);
1157   make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1158 
1159   snprintf(buffer,
1160            sizeof(buffer),
1161            "%s%dm%s%s%dm%s%dm%s%s%dm",
1162            CSI,
1163            F_INTENSITY,
1164            HELLO,
1165            CSI,
1166            F_INTENSITY_OFF1,
1167            CSI,
1168            F_INTENSITY,
1169            HELLO,
1170            CSI,
1171            F_INTENSITY_OFF2);
1172   write_console(&tty_out, buffer);
1173   capture_screen(&tty_out, &actual);
1174 
1175   ASSERT(compare_screen(&tty_out, &actual, &expect));
1176 
1177   /* Set background bright on */
1178   capture_screen(&tty_out, &expect);
1179   cursor_pos.X = expect.si.width / 2;
1180   cursor_pos.Y = expect.si.height / 2;
1181   set_cursor_position(&tty_out, cursor_pos);
1182   attr = expect.si.default_attr;
1183   attr |= BACKGROUND_INTENSITY;
1184   make_expect_screen_write(&expect, cursor_pos, HELLO);
1185   make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1186 
1187   snprintf(buffer,
1188            sizeof(buffer),
1189            "%s%dm%s%s%dm",
1190            CSI,
1191            B_INTENSITY,
1192            HELLO,
1193            CSI,
1194            B_INTENSITY_OFF);
1195   write_console(&tty_out, buffer);
1196   capture_screen(&tty_out, &actual);
1197 
1198   ASSERT(compare_screen(&tty_out, &actual, &expect));
1199 
1200   /* Inverse */
1201   capture_screen(&tty_out, &expect);
1202   cursor_pos.X = expect.si.width / 2;
1203   cursor_pos.Y = expect.si.height / 2;
1204   set_cursor_position(&tty_out, cursor_pos);
1205   attr = expect.si.default_attr;
1206   fg = attr & FOREGROUND_WHITE;
1207   bg = attr & BACKGROUND_WHITE;
1208   attr &= (~FOREGROUND_WHITE & ~BACKGROUND_WHITE);
1209   attr |= COMMON_LVB_REVERSE_VIDEO;
1210   attr |= fg << 4;
1211   attr |= bg >> 4;
1212   make_expect_screen_write(&expect, cursor_pos, HELLO);
1213   make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1214   cursor_pos.X += strlen(HELLO);
1215   make_expect_screen_write(&expect, cursor_pos, HELLO);
1216 
1217   snprintf(buffer,
1218            sizeof(buffer),
1219            "%s%dm%s%s%dm%s",
1220            CSI,
1221            INVERSE,
1222            HELLO,
1223            CSI,
1224            INVERSE_OFF,
1225            HELLO);
1226   write_console(&tty_out, buffer);
1227   capture_screen(&tty_out, &actual);
1228 
1229   ASSERT(compare_screen(&tty_out, &actual, &expect));
1230 
1231   terminate_tty(&tty_out);
1232 
1233   uv_run(loop, UV_RUN_DEFAULT);
1234 
1235   MAKE_VALGRIND_HAPPY();
1236   return 0;
1237 }
1238 
1239 
1240 TEST_IMPL(tty_save_restore_cursor_position) {
1241   uv_tty_t tty_out;
1242   uv_loop_t* loop;
1243   COORD cursor_pos, cursor_pos_old;
1244   char buffer[1024];
1245   struct screen_info si;
1246 
1247   loop = uv_default_loop();
1248 
1249   initialize_tty(&tty_out);
1250   get_screen_info(&tty_out, &si);
1251 
1252   cursor_pos_old.X = si.width / 2;
1253   cursor_pos_old.Y = si.height / 2;
1254   set_cursor_position(&tty_out, cursor_pos_old);
1255 
1256   /* save the cursor position */
1257   snprintf(buffer, sizeof(buffer), "%ss", CSI);
1258   write_console(&tty_out, buffer);
1259 
1260   cursor_pos.X = si.width / 4;
1261   cursor_pos.Y = si.height / 4;
1262   set_cursor_position(&tty_out, cursor_pos);
1263 
1264   /* restore the cursor postion */
1265   snprintf(buffer, sizeof(buffer), "%su", CSI);
1266   write_console(&tty_out, buffer);
1267   get_cursor_position(&tty_out, &cursor_pos);
1268   ASSERT(cursor_pos.X == cursor_pos_old.X);
1269   ASSERT(cursor_pos.Y == cursor_pos_old.Y);
1270 
1271   cursor_pos_old.X = si.width / 2;
1272   cursor_pos_old.Y = si.height / 2;
1273   set_cursor_position(&tty_out, cursor_pos_old);
1274 
1275   /* save the cursor position */
1276   snprintf(buffer, sizeof(buffer), "%s7", ESC);
1277   write_console(&tty_out, buffer);
1278 
1279   cursor_pos.X = si.width / 4;
1280   cursor_pos.Y = si.height / 4;
1281   set_cursor_position(&tty_out, cursor_pos);
1282 
1283   /* restore the cursor postion */
1284   snprintf(buffer, sizeof(buffer), "%s8", ESC);
1285   write_console(&tty_out, buffer);
1286   get_cursor_position(&tty_out, &cursor_pos);
1287   ASSERT(cursor_pos.X == cursor_pos_old.X);
1288   ASSERT(cursor_pos.Y == cursor_pos_old.Y);
1289 
1290   terminate_tty(&tty_out);
1291 
1292   uv_run(loop, UV_RUN_DEFAULT);
1293 
1294   MAKE_VALGRIND_HAPPY();
1295   return 0;
1296 }
1297 
1298 
1299 TEST_IMPL(tty_full_reset) {
1300   uv_tty_t tty_out;
1301   uv_loop_t* loop;
1302   char buffer[1024];
1303   struct captured_screen actual = {0}, expect = {0};
1304   COORD cursor_pos;
1305   DWORD saved_cursor_size;
1306   BOOL saved_cursor_visibility;
1307 
1308   loop = uv_default_loop();
1309 
1310   initialize_tty(&tty_out);
1311 
1312   capture_screen(&tty_out, &expect);
1313   setup_screen(&tty_out);
1314   cursor_pos.X = expect.si.width;
1315   cursor_pos.Y = expect.si.height;
1316   set_cursor_position(&tty_out, cursor_pos);
1317   snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO);
1318   saved_cursor_size = get_cursor_size(&tty_out);
1319   set_cursor_size(&tty_out,
1320                   saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL
1321                                                          : CURSOR_SIZE_LARGE);
1322   saved_cursor_visibility = get_cursor_visibility(&tty_out);
1323   set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE);
1324   write_console(&tty_out, buffer);
1325   snprintf(buffer, sizeof(buffer), "%sc", ESC);
1326   write_console(&tty_out, buffer);
1327   capture_screen(&tty_out, &actual);
1328   ASSERT(compare_screen(&tty_out, &actual, &expect));
1329   ASSERT(get_cursor_size(&tty_out) == saved_cursor_size);
1330   ASSERT(get_cursor_visibility(&tty_out) == saved_cursor_visibility);
1331   ASSERT(actual.si.csbi.srWindow.Top == 0);
1332 
1333   terminate_tty(&tty_out);
1334 
1335   uv_run(loop, UV_RUN_DEFAULT);
1336 
1337   MAKE_VALGRIND_HAPPY();
1338   return 0;
1339 }
1340 
1341 
1342 TEST_IMPL(tty_escape_sequence_processing) {
1343   uv_tty_t tty_out;
1344   uv_loop_t* loop;
1345   COORD cursor_pos, cursor_pos_old;
1346   DWORD saved_cursor_size;
1347   char buffer[1024];
1348   struct captured_screen actual = {0}, expect = {0};
1349   int dir;
1350 
1351   loop = uv_default_loop();
1352 
1353   initialize_tty(&tty_out);
1354 
1355   /* CSI + finaly byte does not output anything */
1356   cursor_pos.X = 1;
1357   cursor_pos.Y = 1;
1358   set_cursor_position(&tty_out, cursor_pos);
1359   capture_screen(&tty_out, &expect);
1360   make_expect_screen_write(&expect, cursor_pos, HELLO);
1361   cursor_pos.X += strlen(HELLO);
1362   make_expect_screen_write(&expect, cursor_pos, HELLO);
1363   snprintf(buffer, sizeof(buffer), "%s@%s%s~%s", CSI, HELLO, CSI, HELLO);
1364   write_console(&tty_out, buffer);
1365   capture_screen(&tty_out, &actual);
1366   ASSERT(compare_screen(&tty_out, &actual, &expect));
1367 
1368   /* CSI(C1) + finaly byte does not output anything */
1369   cursor_pos.X = 1;
1370   cursor_pos.Y = 1;
1371   set_cursor_position(&tty_out, cursor_pos);
1372   capture_screen(&tty_out, &expect);
1373   make_expect_screen_write(&expect, cursor_pos, HELLO);
1374   cursor_pos.X += strlen(HELLO);
1375   make_expect_screen_write(&expect, cursor_pos, HELLO);
1376   snprintf(buffer, sizeof(buffer), "\xC2\x9B@%s\xC2\x9B~%s", HELLO, HELLO);
1377   write_console(&tty_out, buffer);
1378   capture_screen(&tty_out, &actual);
1379   ASSERT(compare_screen(&tty_out, &actual, &expect));
1380 
1381   /* CSI + intermediate byte + finaly byte does not output anything */
1382   cursor_pos.X = 1;
1383   cursor_pos.Y = 1;
1384   set_cursor_position(&tty_out, cursor_pos);
1385   capture_screen(&tty_out, &expect);
1386   make_expect_screen_write(&expect, cursor_pos, HELLO);
1387   cursor_pos.X += strlen(HELLO);
1388   make_expect_screen_write(&expect, cursor_pos, HELLO);
1389   snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO);
1390   write_console(&tty_out, buffer);
1391   capture_screen(&tty_out, &actual);
1392   ASSERT(compare_screen(&tty_out, &actual, &expect));
1393 
1394   /* CSI + parameter byte + finaly byte does not output anything */
1395   cursor_pos.X = 1;
1396   cursor_pos.Y = 1;
1397   set_cursor_position(&tty_out, cursor_pos);
1398   capture_screen(&tty_out, &expect);
1399   snprintf(buffer,
1400            sizeof(buffer),
1401            "%s0@%s%s>~%s%s?~%s",
1402            CSI,
1403            HELLO,
1404            CSI,
1405            HELLO,
1406            CSI,
1407            HELLO);
1408   make_expect_screen_write(&expect, cursor_pos, HELLO);
1409   cursor_pos.X += strlen(HELLO);
1410   make_expect_screen_write(&expect, cursor_pos, HELLO);
1411   cursor_pos.X += strlen(HELLO);
1412   make_expect_screen_write(&expect, cursor_pos, HELLO);
1413   write_console(&tty_out, buffer);
1414   capture_screen(&tty_out, &actual);
1415   ASSERT(compare_screen(&tty_out, &actual, &expect));
1416 
1417   /* ESC Single-char control does not output anyghing */
1418   cursor_pos.X = 1;
1419   cursor_pos.Y = 1;
1420   set_cursor_position(&tty_out, cursor_pos);
1421   capture_screen(&tty_out, &expect);
1422   make_expect_screen_write(&expect, cursor_pos, HELLO);
1423   cursor_pos.X += strlen(HELLO);
1424   make_expect_screen_write(&expect, cursor_pos, HELLO);
1425   snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO);
1426   write_console(&tty_out, buffer);
1427   capture_screen(&tty_out, &actual);
1428   ASSERT(compare_screen(&tty_out, &actual, &expect));
1429 
1430   /* Nothing is output from ESC + ^, _, P, ] to BEL or ESC \ */
1431   /* Operaging System Command */
1432   cursor_pos.X = 1;
1433   cursor_pos.Y = 1;
1434   set_cursor_position(&tty_out, cursor_pos);
1435   capture_screen(&tty_out, &expect);
1436   make_expect_screen_write(&expect, cursor_pos, HELLO);
1437   snprintf(buffer, sizeof(buffer), "%s]0;%s%s%s", ESC, HELLO, BEL, HELLO);
1438   write_console(&tty_out, buffer);
1439   capture_screen(&tty_out, &actual);
1440   ASSERT(compare_screen(&tty_out, &actual, &expect));
1441   /* Device Control Sequence */
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), "%sP$m%s%s", ESC, ST, HELLO);
1448   write_console(&tty_out, buffer);
1449   capture_screen(&tty_out, &actual);
1450   ASSERT(compare_screen(&tty_out, &actual, &expect));
1451   /* Privacy Message */
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,
1458            sizeof(buffer),
1459            "%s^\"%s\\\"%s\"%s%s",
1460            ESC,
1461            HELLO,
1462            HELLO,
1463            ST,
1464            HELLO);
1465   write_console(&tty_out, buffer);
1466   capture_screen(&tty_out, &actual);
1467   ASSERT(compare_screen(&tty_out, &actual, &expect));
1468   /* Application Program Command */
1469   cursor_pos.X = 1;
1470   cursor_pos.Y = 1;
1471   set_cursor_position(&tty_out, cursor_pos);
1472   capture_screen(&tty_out, &expect);
1473   make_expect_screen_write(&expect, cursor_pos, HELLO);
1474   snprintf(buffer,
1475            sizeof(buffer),
1476            "%s_\"%s%s%s\"%s%s",
1477            ESC,
1478            HELLO,
1479            ST,
1480            HELLO,
1481            BEL,
1482            HELLO);
1483   write_console(&tty_out, buffer);
1484   capture_screen(&tty_out, &actual);
1485   ASSERT(compare_screen(&tty_out, &actual, &expect));
1486 
1487   /* Ignore double escape */
1488   cursor_pos.X = 1;
1489   cursor_pos.Y = 1;
1490   set_cursor_position(&tty_out, cursor_pos);
1491   capture_screen(&tty_out, &expect);
1492   make_expect_screen_write(&expect, cursor_pos, HELLO);
1493   cursor_pos.X += strlen(HELLO);
1494   make_expect_screen_write(&expect, cursor_pos, HELLO);
1495   snprintf(buffer,
1496            sizeof(buffer),
1497            "%s%s@%s%s%s~%s",
1498            ESC,
1499            CSI,
1500            HELLO,
1501            ESC,
1502            CSI,
1503            HELLO);
1504   write_console(&tty_out, buffer);
1505   capture_screen(&tty_out, &actual);
1506   ASSERT(compare_screen(&tty_out, &actual, &expect));
1507 
1508   /* Ignored if argument overflow */
1509   set_cursor_to_home(&tty_out);
1510   snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1);
1511   write_console(&tty_out, buffer);
1512   get_cursor_position(&tty_out, &cursor_pos);
1513   ASSERT(cursor_pos.X == 1);
1514   ASSERT(cursor_pos.Y == 1);
1515 
1516   /* Too many argument are ignored */
1517   cursor_pos.X = 1;
1518   cursor_pos.Y = 1;
1519   set_cursor_position(&tty_out, cursor_pos);
1520   capture_screen(&tty_out, &expect);
1521   make_expect_screen_write(&expect, cursor_pos, HELLO);
1522   snprintf(buffer,
1523            sizeof(buffer),
1524            "%s%d;%d;%d;%d;%dm%s%sm",
1525            CSI,
1526            F_RED,
1527            F_INTENSITY,
1528            INVERSE,
1529            B_CYAN,
1530            B_INTENSITY_OFF,
1531            HELLO,
1532            CSI);
1533   write_console(&tty_out, buffer);
1534   capture_screen(&tty_out, &actual);
1535   ASSERT(compare_screen(&tty_out, &actual, &expect));
1536 
1537   /* In the case of DECSCUSR, the others are ignored */
1538   set_cursor_to_home(&tty_out);
1539   snprintf(buffer,
1540            sizeof(buffer),
1541            "%s%d;%d H",
1542            CSI,
1543            expect.si.height / 2,
1544            expect.si.width / 2);
1545   write_console(&tty_out, buffer);
1546   get_cursor_position(&tty_out, &cursor_pos);
1547   ASSERT(cursor_pos.X == 1);
1548   ASSERT(cursor_pos.Y == 1);
1549 
1550   /* Invalid sequence are ignored */
1551   saved_cursor_size = get_cursor_size(&tty_out);
1552   set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1553   snprintf(buffer, sizeof(buffer), "%s 1q", CSI);
1554   write_console(&tty_out, buffer);
1555   ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE);
1556   snprintf(buffer, sizeof(buffer), "%s 1 q", CSI);
1557   write_console(&tty_out, buffer);
1558   ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE);
1559   set_cursor_size(&tty_out, saved_cursor_size);
1560 
1561   /* #1874 2. */
1562   snprintf(buffer, sizeof(buffer), "%s??25l", CSI);
1563   write_console(&tty_out, buffer);
1564   ASSERT(get_cursor_visibility(&tty_out));
1565   snprintf(buffer, sizeof(buffer), "%s25?l", CSI);
1566   write_console(&tty_out, buffer);
1567   ASSERT(get_cursor_visibility(&tty_out));
1568   cursor_pos_old.X = expect.si.width / 2;
1569   cursor_pos_old.Y = expect.si.height / 2;
1570   set_cursor_position(&tty_out, cursor_pos_old);
1571   snprintf(buffer,
1572            sizeof(buffer),
1573            "%s??%d;%df",
1574            CSI,
1575            expect.si.height / 4,
1576            expect.si.width / 4);
1577   write_console(&tty_out, buffer);
1578   get_cursor_position(&tty_out, &cursor_pos);
1579   ASSERT(cursor_pos.X = cursor_pos_old.X);
1580   ASSERT(cursor_pos.Y = cursor_pos_old.Y);
1581   set_cursor_to_home(&tty_out);
1582 
1583   /* CSI 25 l does nothing (#1874 4.) */
1584   snprintf(buffer, sizeof(buffer), "%s25l", CSI);
1585   write_console(&tty_out, buffer);
1586   ASSERT(get_cursor_visibility(&tty_out));
1587 
1588   /* Unsupported sequences are ignored(#1874 5.) */
1589   dir = 2;
1590   setup_screen(&tty_out);
1591   capture_screen(&tty_out, &expect);
1592   set_cursor_position(&tty_out, cursor_pos);
1593   snprintf(buffer, sizeof(buffer), "%s?%dJ", CSI, dir);
1594   write_console(&tty_out, buffer);
1595   capture_screen(&tty_out, &actual);
1596   ASSERT(compare_screen(&tty_out, &actual, &expect));
1597 
1598   /* Finaly byte immedately after CSI [ are also output(#1874 1.) */
1599   cursor_pos.X = expect.si.width / 2;
1600   cursor_pos.Y = expect.si.height / 2;
1601   set_cursor_position(&tty_out, cursor_pos);
1602   capture_screen(&tty_out, &expect);
1603   make_expect_screen_write(&expect, cursor_pos, HELLO);
1604   snprintf(buffer, sizeof(buffer), "%s[%s", CSI, HELLO);
1605   write_console(&tty_out, buffer);
1606   capture_screen(&tty_out, &actual);
1607   ASSERT(compare_screen(&tty_out, &actual, &expect));
1608 
1609   terminate_tty(&tty_out);
1610 
1611   uv_run(loop, UV_RUN_DEFAULT);
1612 
1613   MAKE_VALGRIND_HAPPY();
1614   return 0;
1615 }
1616 
1617 #else
1618 
1619 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
1620 
1621 #endif  /* ifdef _WIN32 */
1622