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
get_screen_info(uv_tty_t * tty_out,struct screen_info * si)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
set_cursor_position(uv_tty_t * tty_out,COORD pos)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
get_cursor_position(uv_tty_t * tty_out,COORD * cursor_position)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
set_cursor_to_home(uv_tty_t * tty_out)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
get_cursor_info(uv_tty_t * tty_out)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
set_cursor_size(uv_tty_t * tty_out,DWORD size)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
get_cursor_size(uv_tty_t * tty_out)140 static DWORD get_cursor_size(uv_tty_t* tty_out) {
141 return get_cursor_info(tty_out).dwSize;
142 }
143
set_cursor_visibility(uv_tty_t * tty_out,BOOL visible)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
get_cursor_visibility(uv_tty_t * tty_out)150 static BOOL get_cursor_visibility(uv_tty_t* tty_out) {
151 return get_cursor_info(tty_out).bVisible;
152 }
153
is_scrolling(uv_tty_t * tty_out,struct screen_info si)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
write_console(uv_tty_t * tty_out,char * src)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
setup_screen(uv_tty_t * tty_out)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
clear_screen(uv_tty_t * tty_out,struct screen_info * si)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
free_screen(struct captured_screen * cs)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
capture_screen(uv_tty_t * tty_out,struct captured_screen * cs)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
make_expect_screen_erase(struct captured_screen * cs,COORD cursor_position,int dir,BOOL entire_screen)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
make_expect_screen_write(struct captured_screen * cs,COORD cursor_position,const char * text)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
make_expect_screen_set_attr(struct captured_screen * cs,COORD cursor_position,size_t length,WORD attr)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
compare_screen(uv_tty_t * tty_out,struct captured_screen * actual,struct captured_screen * expect)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
initialize_tty(uv_tty_t * tty_out)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
terminate_tty(uv_tty_t * tty_out)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
TEST_IMPL(tty_cursor_up)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
TEST_IMPL(tty_cursor_down)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
TEST_IMPL(tty_cursor_forward)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
TEST_IMPL(tty_cursor_back)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
TEST_IMPL(tty_cursor_next_line)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
TEST_IMPL(tty_cursor_previous_line)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
TEST_IMPL(tty_cursor_horizontal_move_absolute)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
TEST_IMPL(tty_cursor_move_absolute)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
TEST_IMPL(tty_hide_show_cursor)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
TEST_IMPL(tty_erase)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
TEST_IMPL(tty_erase_line)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
TEST_IMPL(tty_set_cursor_shape)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
TEST_IMPL(tty_set_style)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
TEST_IMPL(tty_save_restore_cursor_position)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
TEST_IMPL(tty_full_reset)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
TEST_IMPL(tty_escape_sequence_processing)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