libuv-svace-build

Форк
0
/
test-tty-escape-sequence-processing.c 
1632 строки · 49.0 Кб
1
/* Copyright libuv project contributors. All rights reserved.
2
 *
3
 * Permission is hereby granted, free of charge, to any person obtaining a copy
4
 * of this software and associated documentation files (the "Software"), to
5
 * deal in the Software without restriction, including without limitation the
6
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
 * sell copies of the Software, and to permit persons to whom the Software is
8
 * furnished to do so, subject to the following conditions:
9
 *
10
 * The above copyright notice and this permission notice shall be included in
11
 * all copies or substantial portions of the Software.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
 * IN THE SOFTWARE.
20
 */
21

22
#ifdef _WIN32
23

24
#include "task.h"
25
#include "uv.h"
26

27
#include <io.h>
28
#include <windows.h>
29

30
#include <errno.h>
31
#include <string.h>
32

33
#define ESC "\033"
34
#define CSI ESC "["
35
#define ST ESC "\\"
36
#define BEL "\x07"
37
#define HELLO "Hello"
38

39
#define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
40
#define FOREGROUND_BLACK 0
41
#define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN)
42
#define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE)
43
#define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE)
44
#define BACKGROUND_WHITE (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
45
#define BACKGROUND_BLACK 0
46
#define BACKGROUND_YELLOW (BACKGROUND_RED | BACKGROUND_GREEN)
47
#define BACKGROUND_CYAN (BACKGROUND_GREEN | BACKGROUND_BLUE)
48
#define BACKGROUND_MAGENTA (BACKGROUND_RED | BACKGROUND_BLUE)
49

50
#define F_INTENSITY      1
51
#define FB_INTENSITY     2
52
#define B_INTENSITY      5
53
#define INVERSE          7
54
#define F_INTENSITY_OFF1 21
55
#define F_INTENSITY_OFF2 22
56
#define B_INTENSITY_OFF  25
57
#define INVERSE_OFF      27
58
#define F_BLACK          30
59
#define F_RED            31
60
#define F_GREEN          32
61
#define F_YELLOW         33
62
#define F_BLUE           34
63
#define F_MAGENTA        35
64
#define F_CYAN           36
65
#define F_WHITE          37
66
#define F_DEFAULT        39
67
#define B_BLACK          40
68
#define B_RED            41
69
#define B_GREEN          42
70
#define B_YELLOW         43
71
#define B_BLUE           44
72
#define B_MAGENTA        45
73
#define B_CYAN           46
74
#define B_WHITE          47
75
#define B_DEFAULT        49
76

77
#define CURSOR_SIZE_SMALL     25
78
#define CURSOR_SIZE_MIDDLE    50
79
#define CURSOR_SIZE_LARGE     100
80

81
struct screen_info {
82
  CONSOLE_SCREEN_BUFFER_INFO csbi;
83
  int top;
84
  int width;
85
  int height;
86
  int length;
87
  WORD default_attr;
88
};
89

90
struct captured_screen {
91
  char* text;
92
  WORD* attributes;
93
  struct screen_info si;
94
};
95

96
static void get_screen_info(uv_tty_t* tty_out, struct screen_info* si) {
97
  ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &(si->csbi)));
98
  si->width = si->csbi.dwSize.X;
99
  si->height = si->csbi.srWindow.Bottom - si->csbi.srWindow.Top + 1;
100
  si->length = si->width * si->height;
101
  si->default_attr = si->csbi.wAttributes;
102
  si->top = si->csbi.srWindow.Top;
103
}
104

105
static void set_cursor_position(uv_tty_t* tty_out, COORD pos) {
106
  HANDLE handle = tty_out->handle;
107
  CONSOLE_SCREEN_BUFFER_INFO info;
108
  ASSERT(GetConsoleScreenBufferInfo(handle, &info));
109
  pos.X -= 1;
110
  pos.Y += info.srWindow.Top - 1;
111
  ASSERT(SetConsoleCursorPosition(handle, pos));
112
}
113

114
static void get_cursor_position(uv_tty_t* tty_out, COORD* cursor_position) {
115
  HANDLE handle = tty_out->handle;
116
  CONSOLE_SCREEN_BUFFER_INFO info;
117
  ASSERT(GetConsoleScreenBufferInfo(handle, &info));
118
  cursor_position->X = info.dwCursorPosition.X + 1;
119
  cursor_position->Y = info.dwCursorPosition.Y - info.srWindow.Top + 1;
120
}
121

122
static void set_cursor_to_home(uv_tty_t* tty_out) {
123
  COORD origin = {1, 1};
124
  set_cursor_position(tty_out, origin);
125
}
126

127
static CONSOLE_CURSOR_INFO get_cursor_info(uv_tty_t* tty_out) {
128
  HANDLE handle = tty_out->handle;
129
  CONSOLE_CURSOR_INFO info;
130
  ASSERT(GetConsoleCursorInfo(handle, &info));
131
  return info;
132
}
133

134
static void set_cursor_size(uv_tty_t* tty_out, DWORD size) {
135
  CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out);
136
  info.dwSize = size;
137
  ASSERT(SetConsoleCursorInfo(tty_out->handle, &info));
138
}
139

140
static DWORD get_cursor_size(uv_tty_t* tty_out) {
141
  return get_cursor_info(tty_out).dwSize;
142
}
143

144
static void set_cursor_visibility(uv_tty_t* tty_out, BOOL visible) {
145
  CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out);
146
  info.bVisible = visible;
147
  ASSERT(SetConsoleCursorInfo(tty_out->handle, &info));
148
}
149

150
static BOOL get_cursor_visibility(uv_tty_t* tty_out) {
151
  return get_cursor_info(tty_out).bVisible;
152
}
153

154
static BOOL is_scrolling(uv_tty_t* tty_out, struct screen_info si) {
155
  CONSOLE_SCREEN_BUFFER_INFO info;
156
  ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info));
157
  return info.srWindow.Top != si.top;
158
}
159

160
static void write_console(uv_tty_t* tty_out, char* src) {
161
  int r;
162
  uv_buf_t buf;
163

164
  buf.base = src;
165
  buf.len = strlen(buf.base);
166

167
  r = uv_try_write((uv_stream_t*) tty_out, &buf, 1);
168
  ASSERT_GE(r, 0);
169
  ASSERT_EQ((unsigned int) r, buf.len);
170
}
171

172
static void setup_screen(uv_tty_t* tty_out) {
173
  DWORD length, number_of_written;
174
  COORD origin;
175
  CONSOLE_SCREEN_BUFFER_INFO info;
176
  ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info));
177
  length = info.dwSize.X * (info.srWindow.Bottom - info.srWindow.Top + 1);
178
  origin.X = 0;
179
  origin.Y = info.srWindow.Top;
180
  ASSERT(FillConsoleOutputCharacter(
181
         tty_out->handle, '.', length, origin, &number_of_written));
182
  ASSERT_EQ(length, number_of_written);
183
}
184

185
static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) {
186
  DWORD length, number_of_written;
187
  COORD origin;
188
  CONSOLE_SCREEN_BUFFER_INFO info;
189
  ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info));
190
  length = (info.srWindow.Bottom - info.srWindow.Top + 1) * info.dwSize.X - 1;
191
  origin.X = 0;
192
  origin.Y = info.srWindow.Top;
193
  FillConsoleOutputCharacterA(
194
      tty_out->handle, ' ', length, origin, &number_of_written);
195
  ASSERT_EQ(length, number_of_written);
196
  FillConsoleOutputAttribute(
197
      tty_out->handle, si->default_attr, length, origin, &number_of_written);
198
  ASSERT_EQ(length, number_of_written);
199
}
200

201
static void free_screen(struct captured_screen* cs) {
202
  free(cs->text);
203
  cs->text = NULL;
204
  free(cs->attributes);
205
  cs->attributes = NULL;
206
}
207

208
static void capture_screen(uv_tty_t* tty_out, struct captured_screen* cs) {
209
  DWORD length;
210
  COORD origin;
211
  get_screen_info(tty_out, &(cs->si));
212
  origin.X = 0;
213
  origin.Y = cs->si.csbi.srWindow.Top;
214
  cs->text = malloc(cs->si.length * sizeof(*cs->text));
215
  ASSERT_NOT_NULL(cs->text);
216
  cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes));
217
  ASSERT_NOT_NULL(cs->attributes);
218
  ASSERT(ReadConsoleOutputCharacter(
219
         tty_out->handle, cs->text, cs->si.length, origin, &length));
220
  ASSERT_EQ((unsigned int) cs->si.length, length);
221
  ASSERT(ReadConsoleOutputAttribute(
222
         tty_out->handle, cs->attributes, cs->si.length, origin, &length));
223
  ASSERT_EQ((unsigned int) cs->si.length, length);
224
}
225

226
static void make_expect_screen_erase(struct captured_screen* cs,
227
                                     COORD cursor_position,
228
                                     int dir,
229
                                     BOOL entire_screen) {
230
  /* beginning of line */
231
  char* start;
232
  char* end;
233
  start = cs->text + cs->si.width * (cursor_position.Y - 1);
234
  if (dir == 0) {
235
    if (entire_screen) {
236
      /* erase to end of screen */
237
      end = cs->text + cs->si.length;
238
    } else {
239
      /* erase to end of line */
240
      end = start + cs->si.width;
241
    }
242
    /* erase from postition of cursor */
243
    start += cursor_position.X - 1;
244
  } else if (dir == 1) {
245
    /* erase to position of cursor */
246
    end = start + cursor_position.X;
247
    if (entire_screen) {
248
      /* erase form beginning of screen */
249
      start = cs->text;
250
    }
251
  } else if (dir == 2) {
252
    if (entire_screen) {
253
      /* erase form beginning of screen */
254
      start = cs->text;
255
      /* erase to end of screen */
256
      end = cs->text + cs->si.length;
257
    } else {
258
      /* erase to end of line */
259
      end = start + cs->si.width;
260
    }
261
  } else {
262
    ASSERT(FALSE);
263
  }
264
  ASSERT_PTR_LT(start, end);
265
  ASSERT_LE(end - cs->text, cs->si.length);
266
  for (; start < end; start++) {
267
    *start = ' ';
268
  }
269
}
270

271
static void make_expect_screen_write(struct captured_screen* cs,
272
                                     COORD cursor_position,
273
                                     const char* text) {
274
  /* position of cursor */
275
  char* start;
276
  start = cs->text + cs->si.width * (cursor_position.Y - 1) +
277
                cursor_position.X - 1;
278
  size_t length = strlen(text);
279
  size_t remain_length = cs->si.length - (cs->text - start);
280
  length = length > remain_length ? remain_length : length;
281
  memcpy(start, text, length);
282
}
283

284
static void make_expect_screen_set_attr(struct captured_screen* cs,
285
                                        COORD cursor_position,
286
                                        size_t length,
287
                                        WORD attr) {
288
  WORD* start;
289
  start = cs->attributes + cs->si.width * (cursor_position.Y - 1) +
290
                cursor_position.X - 1;
291
  size_t remain_length = cs->si.length - (cs->attributes - start);
292
  length = length > remain_length ? remain_length : length;
293
  while (length) {
294
    *start = attr;
295
    start++;
296
    length--;
297
  }
298
}
299

300
static BOOL compare_screen(uv_tty_t* tty_out,
301
                           struct captured_screen* actual,
302
                           struct captured_screen* expect) {
303
  int line, col;
304
  BOOL result = TRUE;
305
  int current = 0;
306
  ASSERT(actual->text);
307
  ASSERT(actual->attributes);
308
  ASSERT(expect->text);
309
  ASSERT(expect->attributes);
310
  if (actual->si.length != expect->si.length) {
311
    return FALSE;
312
  }
313
  if (actual->si.width != expect->si.width) {
314
    return FALSE;
315
  }
316
  if (actual->si.height != expect->si.height) {
317
    return FALSE;
318
  }
319
  while (current < actual->si.length) {
320
    if (*(actual->text + current) != *(expect->text + current)) {
321
      line = current / actual->si.width + 1;
322
      col = current - actual->si.width * (line - 1) + 1;
323
      fprintf(stderr,
324
              "line:%d col:%d expected character '%c' but found '%c'\n",
325
              line,
326
              col,
327
              *(expect->text + current),
328
              *(actual->text + current));
329
      result = FALSE;
330
    }
331
    if (*(actual->attributes + current) != *(expect->attributes + current)) {
332
      line = current / actual->si.width + 1;
333
      col = current - actual->si.width * (line - 1) + 1;
334
      fprintf(stderr,
335
              "line:%d col:%d expected attributes '%u' but found '%u'\n",
336
              line,
337
              col,
338
              *(expect->attributes + current),
339
              *(actual->attributes + current));
340
      result = FALSE;
341
    }
342
    current++;
343
  }
344
  clear_screen(tty_out, &expect->si);
345
  free_screen(expect);
346
  free_screen(actual);
347
  return result;
348
}
349

350
static void initialize_tty(uv_tty_t* tty_out) {
351
  int r;
352
  int ttyout_fd;
353
  /* Make sure we have an FD that refers to a tty */
354
  HANDLE handle;
355

356
  uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED);
357

358
  handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
359
                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
360
                                     NULL,
361
                                     CONSOLE_TEXTMODE_BUFFER,
362
                                     NULL);
363
  ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE);
364

365
  ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
366
  ASSERT_GE(ttyout_fd, 0);
367
  ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd));
368
  r = uv_tty_init(uv_default_loop(), tty_out, ttyout_fd, 0); /* Writable. */
369
  ASSERT_OK(r);
370
}
371

372
static void terminate_tty(uv_tty_t* tty_out) {
373
  set_cursor_to_home(tty_out);
374
  uv_close((uv_handle_t*) tty_out, NULL);
375
}
376

377
TEST_IMPL(tty_cursor_up) {
378
  uv_tty_t tty_out;
379
  uv_loop_t* loop;
380
  COORD cursor_pos, cursor_pos_old;
381
  char buffer[1024];
382
  struct screen_info si;
383

384
  loop = uv_default_loop();
385

386
  initialize_tty(&tty_out);
387
  get_screen_info(&tty_out, &si);
388

389
  cursor_pos_old.X = si.width / 2;
390
  cursor_pos_old.Y = si.height / 2;
391
  set_cursor_position(&tty_out, cursor_pos_old);
392

393
  /* cursor up one times if omitted arguments */
394
  snprintf(buffer, sizeof(buffer), "%sA", CSI);
395
  write_console(&tty_out, buffer);
396
  get_cursor_position(&tty_out, &cursor_pos);
397
  ASSERT_EQ(cursor_pos_old.Y - 1, cursor_pos.Y);
398
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
399

400
  /* cursor up nth times */
401
  cursor_pos_old = cursor_pos;
402
  snprintf(buffer, sizeof(buffer), "%s%dA", CSI, si.height / 4);
403
  write_console(&tty_out, buffer);
404
  get_cursor_position(&tty_out, &cursor_pos);
405
  ASSERT_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y);
406
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
407

408
  /* cursor up from Window top does nothing */
409
  cursor_pos_old.X = 1;
410
  cursor_pos_old.Y = 1;
411
  set_cursor_position(&tty_out, cursor_pos_old);
412
  snprintf(buffer, sizeof(buffer), "%sA", CSI);
413
  write_console(&tty_out, buffer);
414
  get_cursor_position(&tty_out, &cursor_pos);
415
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
416
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
417
  ASSERT(!is_scrolling(&tty_out, si));
418

419
  terminate_tty(&tty_out);
420

421
  uv_run(loop, UV_RUN_DEFAULT);
422

423
  MAKE_VALGRIND_HAPPY(loop);
424
  return 0;
425
}
426

427

428
TEST_IMPL(tty_cursor_down) {
429
  uv_tty_t tty_out;
430
  uv_loop_t* loop;
431
  COORD cursor_pos, cursor_pos_old;
432
  char buffer[1024];
433
  struct screen_info si;
434

435
  loop = uv_default_loop();
436

437
  initialize_tty(&tty_out);
438
  get_screen_info(&tty_out, &si);
439

440
  cursor_pos_old.X = si.width / 2;
441
  cursor_pos_old.Y = si.height / 2;
442
  set_cursor_position(&tty_out, cursor_pos_old);
443

444
  /* cursor down one times if omitted arguments */
445
  snprintf(buffer, sizeof(buffer), "%sB", CSI);
446
  write_console(&tty_out, buffer);
447
  get_cursor_position(&tty_out, &cursor_pos);
448
  ASSERT_EQ(cursor_pos_old.Y + 1, cursor_pos.Y);
449
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
450

451
  /* cursor down nth times */
452
  cursor_pos_old = cursor_pos;
453
  snprintf(buffer, sizeof(buffer), "%s%dB", CSI, si.height / 4);
454
  write_console(&tty_out, buffer);
455
  get_cursor_position(&tty_out, &cursor_pos);
456
  ASSERT_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y);
457
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
458

459
  /* cursor down from bottom line does nothing */
460
  cursor_pos_old.X = si.width / 2;
461
  cursor_pos_old.Y = si.height;
462
  set_cursor_position(&tty_out, cursor_pos_old);
463
  snprintf(buffer, sizeof(buffer), "%sB", CSI);
464
  write_console(&tty_out, buffer);
465
  get_cursor_position(&tty_out, &cursor_pos);
466
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
467
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
468
  ASSERT(!is_scrolling(&tty_out, si));
469

470
  terminate_tty(&tty_out);
471

472
  uv_run(loop, UV_RUN_DEFAULT);
473

474
  MAKE_VALGRIND_HAPPY(loop);
475
  return 0;
476
}
477

478

479
TEST_IMPL(tty_cursor_forward) {
480
  uv_tty_t tty_out;
481
  uv_loop_t* loop;
482
  COORD cursor_pos, cursor_pos_old;
483
  char buffer[1024];
484
  struct screen_info si;
485

486
  loop = uv_default_loop();
487

488
  initialize_tty(&tty_out);
489
  get_screen_info(&tty_out, &si);
490

491
  cursor_pos_old.X = si.width / 2;
492
  cursor_pos_old.Y = si.height / 2;
493
  set_cursor_position(&tty_out, cursor_pos_old);
494

495
  /* cursor forward one times if omitted arguments */
496
  snprintf(buffer, sizeof(buffer), "%sC", CSI);
497
  write_console(&tty_out, buffer);
498
  get_cursor_position(&tty_out, &cursor_pos);
499
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
500
  ASSERT_EQ(cursor_pos_old.X + 1, cursor_pos.X);
501

502
  /* cursor forward nth times */
503
  cursor_pos_old = cursor_pos;
504
  snprintf(buffer, sizeof(buffer), "%s%dC", CSI, si.width / 4);
505
  write_console(&tty_out, buffer);
506
  get_cursor_position(&tty_out, &cursor_pos);
507
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
508
  ASSERT_EQ(cursor_pos_old.X + si.width / 4, cursor_pos.X);
509

510
  /* cursor forward from end of line does nothing*/
511
  cursor_pos_old.X = si.width;
512
  cursor_pos_old.Y = si.height / 2;
513
  set_cursor_position(&tty_out, cursor_pos_old);
514
  snprintf(buffer, sizeof(buffer), "%sC", CSI);
515
  write_console(&tty_out, buffer);
516
  get_cursor_position(&tty_out, &cursor_pos);
517
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
518
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
519

520
  /* cursor forward from end of screen does nothing */
521
  cursor_pos_old.X = si.width;
522
  cursor_pos_old.Y = si.height;
523
  set_cursor_position(&tty_out, cursor_pos_old);
524
  snprintf(buffer, sizeof(buffer), "%sC", CSI);
525
  write_console(&tty_out, buffer);
526
  get_cursor_position(&tty_out, &cursor_pos);
527
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
528
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
529
  ASSERT(!is_scrolling(&tty_out, si));
530

531
  terminate_tty(&tty_out);
532

533
  uv_run(loop, UV_RUN_DEFAULT);
534

535
  MAKE_VALGRIND_HAPPY(loop);
536
  return 0;
537
}
538

539

540
TEST_IMPL(tty_cursor_back) {
541
  uv_tty_t tty_out;
542
  uv_loop_t* loop;
543
  COORD cursor_pos, cursor_pos_old;
544
  char buffer[1024];
545
  struct screen_info si;
546

547
  loop = uv_default_loop();
548

549
  initialize_tty(&tty_out);
550
  get_screen_info(&tty_out, &si);
551

552
  cursor_pos_old.X = si.width / 2;
553
  cursor_pos_old.Y = si.height / 2;
554
  set_cursor_position(&tty_out, cursor_pos_old);
555

556
  /* cursor back one times if omitted arguments */
557
  snprintf(buffer, sizeof(buffer), "%sD", CSI);
558
  write_console(&tty_out, buffer);
559
  get_cursor_position(&tty_out, &cursor_pos);
560
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
561
  ASSERT_EQ(cursor_pos_old.X - 1, cursor_pos.X);
562

563
  /* cursor back nth times */
564
  cursor_pos_old = cursor_pos;
565
  snprintf(buffer, sizeof(buffer), "%s%dD", CSI, si.width / 4);
566
  write_console(&tty_out, buffer);
567
  get_cursor_position(&tty_out, &cursor_pos);
568
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
569
  ASSERT_EQ(cursor_pos_old.X - si.width / 4, cursor_pos.X);
570

571
  /* cursor back from beginning of line does nothing */
572
  cursor_pos_old.X = 1;
573
  cursor_pos_old.Y = si.height / 2;
574
  set_cursor_position(&tty_out, cursor_pos_old);
575
  snprintf(buffer, sizeof(buffer), "%sD", CSI);
576
  write_console(&tty_out, buffer);
577
  get_cursor_position(&tty_out, &cursor_pos);
578
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
579
  ASSERT_EQ(cursor_pos_old.X, cursor_pos.X);
580

581
  /* cursor back from top of screen does nothing */
582
  cursor_pos_old.X = 1;
583
  cursor_pos_old.Y = 1;
584
  set_cursor_position(&tty_out, cursor_pos_old);
585
  snprintf(buffer, sizeof(buffer), "%sD", CSI);
586
  write_console(&tty_out, buffer);
587
  get_cursor_position(&tty_out, &cursor_pos);
588
  ASSERT_EQ(1, cursor_pos.Y);
589
  ASSERT_EQ(1, cursor_pos.X);
590
  ASSERT(!is_scrolling(&tty_out, si));
591

592
  terminate_tty(&tty_out);
593

594
  uv_run(loop, UV_RUN_DEFAULT);
595

596
  MAKE_VALGRIND_HAPPY(loop);
597
  return 0;
598
}
599

600

601
TEST_IMPL(tty_cursor_next_line) {
602
  uv_tty_t tty_out;
603
  uv_loop_t* loop;
604
  COORD cursor_pos, cursor_pos_old;
605
  char buffer[1024];
606
  struct screen_info si;
607

608
  loop = uv_default_loop();
609

610
  initialize_tty(&tty_out);
611
  get_screen_info(&tty_out, &si);
612

613
  cursor_pos_old.X = si.width / 2;
614
  cursor_pos_old.Y = si.height / 2;
615
  set_cursor_position(&tty_out, cursor_pos_old);
616

617
  /* cursor next line one times if omitted arguments */
618
  snprintf(buffer, sizeof(buffer), "%sE", CSI);
619
  write_console(&tty_out, buffer);
620
  get_cursor_position(&tty_out, &cursor_pos);
621
  ASSERT_EQ(cursor_pos_old.Y + 1, cursor_pos.Y);
622
  ASSERT_EQ(1, cursor_pos.X);
623

624
  /* cursor next line nth times */
625
  cursor_pos_old = cursor_pos;
626
  snprintf(buffer, sizeof(buffer), "%s%dE", CSI, si.height / 4);
627
  write_console(&tty_out, buffer);
628
  get_cursor_position(&tty_out, &cursor_pos);
629
  ASSERT_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y);
630
  ASSERT_EQ(1, cursor_pos.X);
631

632
  /* cursor next line from buttom row moves beginning of line */
633
  cursor_pos_old.X = si.width / 2;
634
  cursor_pos_old.Y = si.height;
635
  set_cursor_position(&tty_out, cursor_pos_old);
636
  snprintf(buffer, sizeof(buffer), "%sE", CSI);
637
  write_console(&tty_out, buffer);
638
  get_cursor_position(&tty_out, &cursor_pos);
639
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
640
  ASSERT_EQ(1, cursor_pos.X);
641
  ASSERT(!is_scrolling(&tty_out, si));
642

643
  terminate_tty(&tty_out);
644

645
  uv_run(loop, UV_RUN_DEFAULT);
646

647
  MAKE_VALGRIND_HAPPY(loop);
648
  return 0;
649
}
650

651

652
TEST_IMPL(tty_cursor_previous_line) {
653
  uv_tty_t tty_out;
654
  uv_loop_t* loop;
655
  COORD cursor_pos, cursor_pos_old;
656
  char buffer[1024];
657
  struct screen_info si;
658

659
  loop = uv_default_loop();
660

661
  initialize_tty(&tty_out);
662
  get_screen_info(&tty_out, &si);
663

664
  cursor_pos_old.X = si.width / 2;
665
  cursor_pos_old.Y = si.height / 2;
666
  set_cursor_position(&tty_out, cursor_pos_old);
667

668
  /* cursor previous line one times if omitted arguments */
669
  snprintf(buffer, sizeof(buffer), "%sF", CSI);
670
  write_console(&tty_out, buffer);
671
  get_cursor_position(&tty_out, &cursor_pos);
672
  ASSERT_EQ(cursor_pos_old.Y - 1, cursor_pos.Y);
673
  ASSERT_EQ(1, cursor_pos.X);
674

675
  /* cursor previous line nth times */
676
  cursor_pos_old = cursor_pos;
677
  snprintf(buffer, sizeof(buffer), "%s%dF", CSI, si.height / 4);
678
  write_console(&tty_out, buffer);
679
  get_cursor_position(&tty_out, &cursor_pos);
680
  ASSERT_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y);
681
  ASSERT_EQ(1, cursor_pos.X);
682

683
  /* cursor previous line from top of screen does nothing */
684
  cursor_pos_old.X = 1;
685
  cursor_pos_old.Y = 1;
686
  set_cursor_position(&tty_out, cursor_pos_old);
687
  snprintf(buffer, sizeof(buffer), "%sD", CSI);
688
  write_console(&tty_out, buffer);
689
  get_cursor_position(&tty_out, &cursor_pos);
690
  ASSERT_EQ(1, cursor_pos.Y);
691
  ASSERT_EQ(1, cursor_pos.X);
692
  ASSERT(!is_scrolling(&tty_out, si));
693

694
  terminate_tty(&tty_out);
695

696
  uv_run(loop, UV_RUN_DEFAULT);
697

698
  MAKE_VALGRIND_HAPPY(loop);
699
  return 0;
700
}
701

702

703
TEST_IMPL(tty_cursor_horizontal_move_absolute) {
704
  uv_tty_t tty_out;
705
  uv_loop_t* loop;
706
  COORD cursor_pos, cursor_pos_old;
707
  char buffer[1024];
708
  struct screen_info si;
709

710
  loop = uv_default_loop();
711

712
  initialize_tty(&tty_out);
713
  get_screen_info(&tty_out, &si);
714

715
  cursor_pos_old.X = si.width / 2;
716
  cursor_pos_old.Y = si.height / 2;
717
  set_cursor_position(&tty_out, cursor_pos_old);
718

719
  /* Move to beginning of line if omitted argument */
720
  snprintf(buffer, sizeof(buffer), "%sG", CSI);
721
  write_console(&tty_out, buffer);
722
  get_cursor_position(&tty_out, &cursor_pos);
723
  ASSERT_EQ(1, cursor_pos.X);
724
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
725

726
  /* Move cursor to nth character */
727
  snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width / 4);
728
  write_console(&tty_out, buffer);
729
  get_cursor_position(&tty_out, &cursor_pos);
730
  ASSERT_EQ(si.width / 4, cursor_pos.X);
731
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
732

733
  /* Moving out of screen will fit within screen */
734
  snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width + 1);
735
  write_console(&tty_out, buffer);
736
  get_cursor_position(&tty_out, &cursor_pos);
737
  ASSERT_EQ(si.width, cursor_pos.X);
738
  ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y);
739

740
  terminate_tty(&tty_out);
741

742
  uv_run(loop, UV_RUN_DEFAULT);
743

744
  MAKE_VALGRIND_HAPPY(loop);
745
  return 0;
746
}
747

748

749
TEST_IMPL(tty_cursor_move_absolute) {
750
  uv_tty_t tty_out;
751
  uv_loop_t* loop;
752
  COORD cursor_pos;
753
  char buffer[1024];
754
  struct screen_info si;
755

756
  loop = uv_default_loop();
757

758
  initialize_tty(&tty_out);
759
  get_screen_info(&tty_out, &si);
760

761
  cursor_pos.X = si.width / 2;
762
  cursor_pos.Y = si.height / 2;
763
  set_cursor_position(&tty_out, cursor_pos);
764

765
  /* Move the cursor to home if omitted arguments */
766
  snprintf(buffer, sizeof(buffer), "%sH", CSI);
767
  write_console(&tty_out, buffer);
768
  get_cursor_position(&tty_out, &cursor_pos);
769
  ASSERT_EQ(1, cursor_pos.X);
770
  ASSERT_EQ(1, cursor_pos.Y);
771

772
  /* Move the cursor to the middle of the screen */
773
  snprintf(
774
      buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width / 2);
775
  write_console(&tty_out, buffer);
776
  get_cursor_position(&tty_out, &cursor_pos);
777
  ASSERT_EQ(si.width / 2, cursor_pos.X);
778
  ASSERT_EQ(si.height / 2, cursor_pos.Y);
779

780
  /* Moving out of screen will fit within screen */
781
  snprintf(
782
      buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width + 1);
783
  write_console(&tty_out, buffer);
784
  get_cursor_position(&tty_out, &cursor_pos);
785
  ASSERT_EQ(si.width, cursor_pos.X);
786
  ASSERT_EQ(si.height / 2, cursor_pos.Y);
787

788
  snprintf(
789
      buffer, sizeof(buffer), "%s%d;%df", CSI, si.height + 1, si.width / 2);
790
  write_console(&tty_out, buffer);
791
  get_cursor_position(&tty_out, &cursor_pos);
792
  ASSERT_EQ(si.width / 2, cursor_pos.X);
793
  ASSERT_EQ(si.height, cursor_pos.Y);
794
  ASSERT(!is_scrolling(&tty_out, si));
795

796
  terminate_tty(&tty_out);
797

798
  uv_run(loop, UV_RUN_DEFAULT);
799

800
  MAKE_VALGRIND_HAPPY(loop);
801
  return 0;
802
}
803

804

805
TEST_IMPL(tty_hide_show_cursor) {
806
  uv_tty_t tty_out;
807
  uv_loop_t* loop;
808
  char buffer[1024];
809
  BOOL saved_cursor_visibility;
810

811
  loop = uv_default_loop();
812

813
  initialize_tty(&tty_out);
814

815
  saved_cursor_visibility = get_cursor_visibility(&tty_out);
816

817
  /* Hide the cursor */
818
  set_cursor_visibility(&tty_out, TRUE);
819
  snprintf(buffer, sizeof(buffer), "%s?25l", CSI);
820
  write_console(&tty_out, buffer);
821
  ASSERT(!get_cursor_visibility(&tty_out));
822

823
  /* Show the cursor */
824
  set_cursor_visibility(&tty_out, FALSE);
825
  snprintf(buffer, sizeof(buffer), "%s?25h", CSI);
826
  write_console(&tty_out, buffer);
827
  ASSERT(get_cursor_visibility(&tty_out));
828

829
  set_cursor_visibility(&tty_out, saved_cursor_visibility);
830
  terminate_tty(&tty_out);
831

832
  uv_run(loop, UV_RUN_DEFAULT);
833

834
  MAKE_VALGRIND_HAPPY(loop);
835
  return 0;
836
}
837

838

839
TEST_IMPL(tty_erase) {
840
  int dir;
841
  uv_tty_t tty_out;
842
  uv_loop_t* loop;
843
  COORD cursor_pos;
844
  char buffer[1024];
845
  struct captured_screen actual = {0}, expect = {0};
846

847
  loop = uv_default_loop();
848

849
  initialize_tty(&tty_out);
850

851
  /* Erase to below if omitted argument */
852
  dir = 0;
853
  setup_screen(&tty_out);
854
  capture_screen(&tty_out, &expect);
855
  cursor_pos.X = expect.si.width / 2;
856
  cursor_pos.Y = expect.si.height / 2;
857
  make_expect_screen_erase(&expect, cursor_pos, dir, TRUE);
858

859
  set_cursor_position(&tty_out, cursor_pos);
860
  snprintf(buffer, sizeof(buffer), "%sJ", CSI);
861
  write_console(&tty_out, buffer);
862
  capture_screen(&tty_out, &actual);
863

864
  ASSERT(compare_screen(&tty_out, &actual, &expect));
865

866
  /* Erase to below(dir = 0) */
867
  setup_screen(&tty_out);
868
  capture_screen(&tty_out, &expect);
869
  make_expect_screen_erase(&expect, cursor_pos, dir, TRUE);
870

871
  set_cursor_position(&tty_out, cursor_pos);
872
  snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir);
873
  write_console(&tty_out, buffer);
874
  capture_screen(&tty_out, &actual);
875

876
  ASSERT(compare_screen(&tty_out, &actual, &expect));
877

878
  /* Erase to above */
879
  dir = 1;
880
  setup_screen(&tty_out);
881
  capture_screen(&tty_out, &expect);
882
  make_expect_screen_erase(&expect, cursor_pos, dir, TRUE);
883

884
  set_cursor_position(&tty_out, cursor_pos);
885
  snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir);
886
  write_console(&tty_out, buffer);
887
  capture_screen(&tty_out, &actual);
888

889
  ASSERT(compare_screen(&tty_out, &actual, &expect));
890

891
  /* Erase All */
892
  dir = 2;
893
  setup_screen(&tty_out);
894
  capture_screen(&tty_out, &expect);
895
  make_expect_screen_erase(&expect, cursor_pos, dir, TRUE);
896

897
  set_cursor_position(&tty_out, cursor_pos);
898
  snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir);
899
  write_console(&tty_out, buffer);
900
  capture_screen(&tty_out, &actual);
901

902
  ASSERT(compare_screen(&tty_out, &actual, &expect));
903

904
  terminate_tty(&tty_out);
905

906
  uv_run(loop, UV_RUN_DEFAULT);
907

908
  MAKE_VALGRIND_HAPPY(loop);
909
  return 0;
910
}
911

912

913
TEST_IMPL(tty_erase_line) {
914
  int dir;
915
  uv_tty_t tty_out;
916
  uv_loop_t* loop;
917
  COORD cursor_pos;
918
  char buffer[1024];
919
  struct captured_screen actual = {0}, expect = {0};
920

921
  loop = uv_default_loop();
922

923
  initialize_tty(&tty_out);
924

925
  /* Erase to right if omitted arguments */
926
  dir = 0;
927
  setup_screen(&tty_out);
928
  capture_screen(&tty_out, &expect);
929
  cursor_pos.X = expect.si.width / 2;
930
  cursor_pos.Y = expect.si.height / 2;
931
  make_expect_screen_erase(&expect, cursor_pos, dir, FALSE);
932

933
  set_cursor_position(&tty_out, cursor_pos);
934
  snprintf(buffer, sizeof(buffer), "%sK", CSI);
935
  write_console(&tty_out, buffer);
936
  capture_screen(&tty_out, &actual);
937

938
  ASSERT(compare_screen(&tty_out, &actual, &expect));
939

940
  /* Erase to right(dir = 0) */
941
  setup_screen(&tty_out);
942
  capture_screen(&tty_out, &expect);
943
  make_expect_screen_erase(&expect, cursor_pos, dir, FALSE);
944

945
  set_cursor_position(&tty_out, cursor_pos);
946
  snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir);
947
  write_console(&tty_out, buffer);
948
  capture_screen(&tty_out, &actual);
949

950
  ASSERT(compare_screen(&tty_out, &actual, &expect));
951

952
  /* Erase to Left */
953
  dir = 1;
954
  setup_screen(&tty_out);
955
  capture_screen(&tty_out, &expect);
956
  make_expect_screen_erase(&expect, cursor_pos, dir, FALSE);
957

958
  set_cursor_position(&tty_out, cursor_pos);
959
  snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir);
960
  write_console(&tty_out, buffer);
961
  capture_screen(&tty_out, &actual);
962

963
  ASSERT(compare_screen(&tty_out, &actual, &expect));
964

965
  /* Erase All */
966
  dir = 2;
967
  setup_screen(&tty_out);
968
  capture_screen(&tty_out, &expect);
969
  make_expect_screen_erase(&expect, cursor_pos, dir, FALSE);
970

971
  set_cursor_position(&tty_out, cursor_pos);
972
  snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir);
973
  write_console(&tty_out, buffer);
974
  capture_screen(&tty_out, &actual);
975

976
  ASSERT(compare_screen(&tty_out, &actual, &expect));
977

978
  terminate_tty(&tty_out);
979

980
  uv_run(loop, UV_RUN_DEFAULT);
981

982
  MAKE_VALGRIND_HAPPY(loop);
983
  return 0;
984
}
985

986

987
TEST_IMPL(tty_set_cursor_shape) {
988
  uv_tty_t tty_out;
989
  uv_loop_t* loop;
990
  DWORD saved_cursor_size;
991
  char buffer[1024];
992

993
  loop = uv_default_loop();
994

995
  initialize_tty(&tty_out);
996

997
  saved_cursor_size = get_cursor_size(&tty_out);
998

999
  /* cursor size large if omitted arguments */
1000
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1001
  snprintf(buffer, sizeof(buffer), "%s q", CSI);
1002
  write_console(&tty_out, buffer);
1003
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE);
1004

1005
  /* cursor size large */
1006
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1007
  snprintf(buffer, sizeof(buffer), "%s1 q", CSI);
1008
  write_console(&tty_out, buffer);
1009
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE);
1010
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1011
  snprintf(buffer, sizeof(buffer), "%s2 q", CSI);
1012
  write_console(&tty_out, buffer);
1013
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE);
1014

1015
  /* cursor size small */
1016
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1017
  snprintf(buffer, sizeof(buffer), "%s3 q", CSI);
1018
  write_console(&tty_out, buffer);
1019
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_SMALL);
1020
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1021
  snprintf(buffer, sizeof(buffer), "%s6 q", CSI);
1022
  write_console(&tty_out, buffer);
1023
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_SMALL);
1024

1025
  /* Nothing occurs with arguments outside valid range */
1026
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1027
  snprintf(buffer, sizeof(buffer), "%s7 q", CSI);
1028
  write_console(&tty_out, buffer);
1029
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE);
1030

1031
  /* restore cursor size if arguments is zero */
1032
  snprintf(buffer, sizeof(buffer), "%s0 q", CSI);
1033
  write_console(&tty_out, buffer);
1034
  ASSERT_EQ(get_cursor_size(&tty_out), saved_cursor_size);
1035

1036
  terminate_tty(&tty_out);
1037

1038
  uv_run(loop, UV_RUN_DEFAULT);
1039

1040
  MAKE_VALGRIND_HAPPY(loop);
1041
  return 0;
1042
}
1043

1044

1045
TEST_IMPL(tty_set_style) {
1046
#if _MSC_VER >= 1920 && _MSC_VER <= 1929
1047
  RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. "
1048
              "See: https://github.com/libuv/libuv/issues/3304");
1049
#else
1050

1051
  uv_tty_t tty_out;
1052
  uv_loop_t* loop;
1053
  COORD cursor_pos;
1054
  char buffer[1024];
1055
  struct captured_screen actual = {0}, expect = {0};
1056
  WORD fg, bg;
1057
  WORD fg_attrs[9][2] = {{F_BLACK, FOREGROUND_BLACK},
1058
                         {F_RED, FOREGROUND_RED},
1059
                         {F_GREEN, FOREGROUND_GREEN},
1060
                         {F_YELLOW, FOREGROUND_YELLOW},
1061
                         {F_BLUE, FOREGROUND_BLUE},
1062
                         {F_MAGENTA, FOREGROUND_MAGENTA},
1063
                         {F_CYAN, FOREGROUND_CYAN},
1064
                         {F_WHITE, FOREGROUND_WHITE},
1065
                         {F_DEFAULT, 0}};
1066
  WORD bg_attrs[9][2] = {{B_DEFAULT, 0},
1067
                         {B_BLACK, BACKGROUND_BLACK},
1068
                         {B_RED, BACKGROUND_RED},
1069
                         {B_GREEN, BACKGROUND_GREEN},
1070
                         {B_YELLOW, BACKGROUND_YELLOW},
1071
                         {B_BLUE, BACKGROUND_BLUE},
1072
                         {B_MAGENTA, BACKGROUND_MAGENTA},
1073
                         {B_CYAN, BACKGROUND_CYAN},
1074
                         {B_WHITE, BACKGROUND_WHITE}};
1075
  WORD attr;
1076
  int i, length;
1077

1078
  loop = uv_default_loop();
1079

1080
  initialize_tty(&tty_out);
1081

1082
  capture_screen(&tty_out, &expect);
1083
  fg_attrs[8][1] = expect.si.default_attr & FOREGROUND_WHITE;
1084
  bg_attrs[0][1] = expect.si.default_attr & BACKGROUND_WHITE;
1085

1086
  /* Set foreground color */
1087
  length = ARRAY_SIZE(fg_attrs);
1088
  for (i = 0; i < length; i++) {
1089
    capture_screen(&tty_out, &expect);
1090
    cursor_pos.X = expect.si.width / 2;
1091
    cursor_pos.Y = expect.si.height / 2;
1092
    attr = (expect.si.default_attr & ~FOREGROUND_WHITE) | fg_attrs[i][1];
1093
    make_expect_screen_write(&expect, cursor_pos, HELLO);
1094
    make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1095

1096
    set_cursor_position(&tty_out, cursor_pos);
1097
    snprintf(
1098
        buffer, sizeof(buffer), "%s%dm%s%sm", CSI, fg_attrs[i][0], HELLO, CSI);
1099
    write_console(&tty_out, buffer);
1100
    capture_screen(&tty_out, &actual);
1101

1102
    ASSERT(compare_screen(&tty_out, &actual, &expect));
1103
  }
1104

1105
  /* Set background color */
1106
  length = ARRAY_SIZE(bg_attrs);
1107
  for (i = 0; i < length; i++) {
1108
    capture_screen(&tty_out, &expect);
1109
    cursor_pos.X = expect.si.width / 2;
1110
    cursor_pos.Y = expect.si.height / 2;
1111
    attr = (expect.si.default_attr & ~BACKGROUND_WHITE) | bg_attrs[i][1];
1112
    make_expect_screen_write(&expect, cursor_pos, HELLO);
1113
    make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1114

1115
    set_cursor_position(&tty_out, cursor_pos);
1116
    snprintf(
1117
        buffer, sizeof(buffer), "%s%dm%s%sm", CSI, bg_attrs[i][0], HELLO, CSI);
1118
    write_console(&tty_out, buffer);
1119
    capture_screen(&tty_out, &actual);
1120

1121
    ASSERT(compare_screen(&tty_out, &actual, &expect));
1122
  }
1123

1124
  /* Set foreground and background color */
1125
  ASSERT_EQ(ARRAY_SIZE(fg_attrs), ARRAY_SIZE(bg_attrs));
1126
  length = ARRAY_SIZE(bg_attrs);
1127
  for (i = 0; i < length; i++) {
1128
    capture_screen(&tty_out, &expect);
1129
    cursor_pos.X = expect.si.width / 2;
1130
    cursor_pos.Y = expect.si.height / 2;
1131
    attr = expect.si.default_attr & ~FOREGROUND_WHITE & ~BACKGROUND_WHITE;
1132
    attr |= fg_attrs[i][1] | bg_attrs[i][1];
1133
    make_expect_screen_write(&expect, cursor_pos, HELLO);
1134
    make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1135

1136
    set_cursor_position(&tty_out, cursor_pos);
1137
    snprintf(buffer,
1138
             sizeof(buffer),
1139
             "%s%d;%dm%s%sm",
1140
             CSI,
1141
             bg_attrs[i][0],
1142
             fg_attrs[i][0],
1143
             HELLO,
1144
             CSI);
1145
    write_console(&tty_out, buffer);
1146
    capture_screen(&tty_out, &actual);
1147

1148
    ASSERT(compare_screen(&tty_out, &actual, &expect));
1149
  }
1150

1151
  /* Set foreground bright on */
1152
  capture_screen(&tty_out, &expect);
1153
  cursor_pos.X = expect.si.width / 2;
1154
  cursor_pos.Y = expect.si.height / 2;
1155
  set_cursor_position(&tty_out, cursor_pos);
1156
  attr = expect.si.default_attr;
1157
  attr |= FOREGROUND_INTENSITY;
1158
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1159
  make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1160
  cursor_pos.X += strlen(HELLO);
1161
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1162
  make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1163

1164
  snprintf(buffer,
1165
           sizeof(buffer),
1166
           "%s%dm%s%s%dm%s%dm%s%s%dm",
1167
           CSI,
1168
           F_INTENSITY,
1169
           HELLO,
1170
           CSI,
1171
           F_INTENSITY_OFF1,
1172
           CSI,
1173
           F_INTENSITY,
1174
           HELLO,
1175
           CSI,
1176
           F_INTENSITY_OFF2);
1177
  write_console(&tty_out, buffer);
1178
  capture_screen(&tty_out, &actual);
1179

1180
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1181

1182
  /* Set background bright on */
1183
  capture_screen(&tty_out, &expect);
1184
  cursor_pos.X = expect.si.width / 2;
1185
  cursor_pos.Y = expect.si.height / 2;
1186
  set_cursor_position(&tty_out, cursor_pos);
1187
  attr = expect.si.default_attr;
1188
  attr |= BACKGROUND_INTENSITY;
1189
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1190
  make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1191

1192
  snprintf(buffer,
1193
           sizeof(buffer),
1194
           "%s%dm%s%s%dm",
1195
           CSI,
1196
           B_INTENSITY,
1197
           HELLO,
1198
           CSI,
1199
           B_INTENSITY_OFF);
1200
  write_console(&tty_out, buffer);
1201
  capture_screen(&tty_out, &actual);
1202

1203
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1204

1205
  /* Inverse */
1206
  capture_screen(&tty_out, &expect);
1207
  cursor_pos.X = expect.si.width / 2;
1208
  cursor_pos.Y = expect.si.height / 2;
1209
  set_cursor_position(&tty_out, cursor_pos);
1210
  attr = expect.si.default_attr;
1211
  fg = attr & FOREGROUND_WHITE;
1212
  bg = attr & BACKGROUND_WHITE;
1213
  attr &= (~FOREGROUND_WHITE & ~BACKGROUND_WHITE);
1214
  attr |= COMMON_LVB_REVERSE_VIDEO;
1215
  attr |= fg << 4;
1216
  attr |= bg >> 4;
1217
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1218
  make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr);
1219
  cursor_pos.X += strlen(HELLO);
1220
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1221

1222
  snprintf(buffer,
1223
           sizeof(buffer),
1224
           "%s%dm%s%s%dm%s",
1225
           CSI,
1226
           INVERSE,
1227
           HELLO,
1228
           CSI,
1229
           INVERSE_OFF,
1230
           HELLO);
1231
  write_console(&tty_out, buffer);
1232
  capture_screen(&tty_out, &actual);
1233

1234
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1235

1236
  terminate_tty(&tty_out);
1237

1238
  uv_run(loop, UV_RUN_DEFAULT);
1239

1240
  MAKE_VALGRIND_HAPPY(loop);
1241
  return 0;
1242
#endif
1243
}
1244

1245

1246
TEST_IMPL(tty_save_restore_cursor_position) {
1247
  uv_tty_t tty_out;
1248
  uv_loop_t* loop;
1249
  COORD cursor_pos, cursor_pos_old;
1250
  char buffer[1024];
1251
  struct screen_info si;
1252

1253
  loop = uv_default_loop();
1254

1255
  initialize_tty(&tty_out);
1256
  get_screen_info(&tty_out, &si);
1257

1258
  cursor_pos_old.X = si.width / 2;
1259
  cursor_pos_old.Y = si.height / 2;
1260
  set_cursor_position(&tty_out, cursor_pos_old);
1261

1262
  /* save the cursor position */
1263
  snprintf(buffer, sizeof(buffer), "%ss", CSI);
1264
  write_console(&tty_out, buffer);
1265

1266
  cursor_pos.X = si.width / 4;
1267
  cursor_pos.Y = si.height / 4;
1268
  set_cursor_position(&tty_out, cursor_pos);
1269

1270
  /* restore the cursor position */
1271
  snprintf(buffer, sizeof(buffer), "%su", CSI);
1272
  write_console(&tty_out, buffer);
1273
  get_cursor_position(&tty_out, &cursor_pos);
1274
  ASSERT_EQ(cursor_pos.X, cursor_pos_old.X);
1275
  ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y);
1276

1277
  cursor_pos_old.X = si.width / 2;
1278
  cursor_pos_old.Y = si.height / 2;
1279
  set_cursor_position(&tty_out, cursor_pos_old);
1280

1281
  /* save the cursor position */
1282
  snprintf(buffer, sizeof(buffer), "%s7", ESC);
1283
  write_console(&tty_out, buffer);
1284

1285
  cursor_pos.X = si.width / 4;
1286
  cursor_pos.Y = si.height / 4;
1287
  set_cursor_position(&tty_out, cursor_pos);
1288

1289
  /* restore the cursor position */
1290
  snprintf(buffer, sizeof(buffer), "%s8", ESC);
1291
  write_console(&tty_out, buffer);
1292
  get_cursor_position(&tty_out, &cursor_pos);
1293
  ASSERT_EQ(cursor_pos.X, cursor_pos_old.X);
1294
  ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y);
1295

1296
  terminate_tty(&tty_out);
1297

1298
  uv_run(loop, UV_RUN_DEFAULT);
1299

1300
  MAKE_VALGRIND_HAPPY(loop);
1301
  return 0;
1302
}
1303

1304

1305
TEST_IMPL(tty_full_reset) {
1306
  uv_tty_t tty_out;
1307
  uv_loop_t* loop;
1308
  char buffer[1024];
1309
  struct captured_screen actual = {0}, expect = {0};
1310
  COORD cursor_pos;
1311
  DWORD saved_cursor_size;
1312
  BOOL saved_cursor_visibility;
1313

1314
  loop = uv_default_loop();
1315

1316
  initialize_tty(&tty_out);
1317

1318
  capture_screen(&tty_out, &expect);
1319
  setup_screen(&tty_out);
1320
  cursor_pos.X = expect.si.width;
1321
  cursor_pos.Y = expect.si.height;
1322
  set_cursor_position(&tty_out, cursor_pos);
1323
  snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO);
1324
  saved_cursor_size = get_cursor_size(&tty_out);
1325
  set_cursor_size(&tty_out,
1326
                  saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL
1327
                                                         : CURSOR_SIZE_LARGE);
1328
  saved_cursor_visibility = get_cursor_visibility(&tty_out);
1329
  set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE);
1330
  write_console(&tty_out, buffer);
1331
  snprintf(buffer, sizeof(buffer), "%sc", ESC);
1332
  write_console(&tty_out, buffer);
1333
  capture_screen(&tty_out, &actual);
1334
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1335
  ASSERT_EQ(get_cursor_size(&tty_out), saved_cursor_size);
1336
  ASSERT_EQ(get_cursor_visibility(&tty_out), saved_cursor_visibility);
1337
  ASSERT_OK(actual.si.csbi.srWindow.Top);
1338

1339
  terminate_tty(&tty_out);
1340

1341
  uv_run(loop, UV_RUN_DEFAULT);
1342

1343
  MAKE_VALGRIND_HAPPY(loop);
1344
  return 0;
1345
}
1346

1347

1348
TEST_IMPL(tty_escape_sequence_processing) {
1349
#if _MSC_VER >= 1920 && _MSC_VER <= 1929
1350
  RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. "
1351
              "See: https://github.com/libuv/libuv/issues/3304");
1352
#else
1353
  uv_tty_t tty_out;
1354
  uv_loop_t* loop;
1355
  COORD cursor_pos, cursor_pos_old;
1356
  DWORD saved_cursor_size;
1357
  char buffer[1024];
1358
  struct captured_screen actual = {0}, expect = {0};
1359
  int dir;
1360

1361
  loop = uv_default_loop();
1362

1363
  initialize_tty(&tty_out);
1364

1365
  /* CSI + finally byte does not output anything */
1366
  cursor_pos.X = 1;
1367
  cursor_pos.Y = 1;
1368
  set_cursor_position(&tty_out, cursor_pos);
1369
  capture_screen(&tty_out, &expect);
1370
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1371
  cursor_pos.X += strlen(HELLO);
1372
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1373
  snprintf(buffer, sizeof(buffer), "%s@%s%s~%s", CSI, HELLO, CSI, HELLO);
1374
  write_console(&tty_out, buffer);
1375
  capture_screen(&tty_out, &actual);
1376
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1377

1378
  /* CSI(C1) + finally byte does not output anything */
1379
  cursor_pos.X = 1;
1380
  cursor_pos.Y = 1;
1381
  set_cursor_position(&tty_out, cursor_pos);
1382
  capture_screen(&tty_out, &expect);
1383
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1384
  cursor_pos.X += strlen(HELLO);
1385
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1386
  snprintf(buffer, sizeof(buffer), "\xC2\x9B@%s\xC2\x9B~%s", HELLO, HELLO);
1387
  write_console(&tty_out, buffer);
1388
  capture_screen(&tty_out, &actual);
1389
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1390

1391
  /* CSI + intermediate byte + finally byte does not output anything */
1392
  cursor_pos.X = 1;
1393
  cursor_pos.Y = 1;
1394
  set_cursor_position(&tty_out, cursor_pos);
1395
  capture_screen(&tty_out, &expect);
1396
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1397
  cursor_pos.X += strlen(HELLO);
1398
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1399
  snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO);
1400
  write_console(&tty_out, buffer);
1401
  capture_screen(&tty_out, &actual);
1402
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1403

1404
  /* CSI + parameter byte + finally byte does not output anything */
1405
  cursor_pos.X = 1;
1406
  cursor_pos.Y = 1;
1407
  set_cursor_position(&tty_out, cursor_pos);
1408
  capture_screen(&tty_out, &expect);
1409
  snprintf(buffer,
1410
           sizeof(buffer),
1411
           "%s0@%s%s>~%s%s?~%s",
1412
           CSI,
1413
           HELLO,
1414
           CSI,
1415
           HELLO,
1416
           CSI,
1417
           HELLO);
1418
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1419
  cursor_pos.X += strlen(HELLO);
1420
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1421
  cursor_pos.X += strlen(HELLO);
1422
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1423
  write_console(&tty_out, buffer);
1424
  capture_screen(&tty_out, &actual);
1425
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1426

1427
  /* ESC Single-char control does not output anyghing */
1428
  cursor_pos.X = 1;
1429
  cursor_pos.Y = 1;
1430
  set_cursor_position(&tty_out, cursor_pos);
1431
  capture_screen(&tty_out, &expect);
1432
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1433
  cursor_pos.X += strlen(HELLO);
1434
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1435
  snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO);
1436
  write_console(&tty_out, buffer);
1437
  capture_screen(&tty_out, &actual);
1438
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1439

1440
  /* Nothing is output from ESC + ^, _, P, ] to BEL or ESC \ */
1441
  /* Operaging System Command */
1442
  cursor_pos.X = 1;
1443
  cursor_pos.Y = 1;
1444
  set_cursor_position(&tty_out, cursor_pos);
1445
  capture_screen(&tty_out, &expect);
1446
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1447
  snprintf(buffer, sizeof(buffer), "%s]0;%s%s%s", ESC, HELLO, BEL, HELLO);
1448
  write_console(&tty_out, buffer);
1449
  capture_screen(&tty_out, &actual);
1450
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1451
  /* Device Control Sequence */
1452
  cursor_pos.X = 1;
1453
  cursor_pos.Y = 1;
1454
  set_cursor_position(&tty_out, cursor_pos);
1455
  capture_screen(&tty_out, &expect);
1456
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1457
  snprintf(buffer, sizeof(buffer), "%sP$m%s%s", ESC, ST, HELLO);
1458
  write_console(&tty_out, buffer);
1459
  capture_screen(&tty_out, &actual);
1460
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1461
  /* Privacy Message */
1462
  cursor_pos.X = 1;
1463
  cursor_pos.Y = 1;
1464
  set_cursor_position(&tty_out, cursor_pos);
1465
  capture_screen(&tty_out, &expect);
1466
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1467
  snprintf(buffer,
1468
           sizeof(buffer),
1469
           "%s^\"%s\\\"%s\"%s%s",
1470
           ESC,
1471
           HELLO,
1472
           HELLO,
1473
           ST,
1474
           HELLO);
1475
  write_console(&tty_out, buffer);
1476
  capture_screen(&tty_out, &actual);
1477
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1478
  /* Application Program Command */
1479
  cursor_pos.X = 1;
1480
  cursor_pos.Y = 1;
1481
  set_cursor_position(&tty_out, cursor_pos);
1482
  capture_screen(&tty_out, &expect);
1483
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1484
  snprintf(buffer,
1485
           sizeof(buffer),
1486
           "%s_\"%s%s%s\"%s%s",
1487
           ESC,
1488
           HELLO,
1489
           ST,
1490
           HELLO,
1491
           BEL,
1492
           HELLO);
1493
  write_console(&tty_out, buffer);
1494
  capture_screen(&tty_out, &actual);
1495
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1496

1497
  /* Ignore double escape */
1498
  cursor_pos.X = 1;
1499
  cursor_pos.Y = 1;
1500
  set_cursor_position(&tty_out, cursor_pos);
1501
  capture_screen(&tty_out, &expect);
1502
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1503
  cursor_pos.X += strlen(HELLO);
1504
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1505
  snprintf(buffer,
1506
           sizeof(buffer),
1507
           "%s%s@%s%s%s~%s",
1508
           ESC,
1509
           CSI,
1510
           HELLO,
1511
           ESC,
1512
           CSI,
1513
           HELLO);
1514
  write_console(&tty_out, buffer);
1515
  capture_screen(&tty_out, &actual);
1516
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1517

1518
  /* Ignored if argument overflow */
1519
  set_cursor_to_home(&tty_out);
1520
  snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1);
1521
  write_console(&tty_out, buffer);
1522
  get_cursor_position(&tty_out, &cursor_pos);
1523
  ASSERT_EQ(1, cursor_pos.X);
1524
  ASSERT_EQ(1, cursor_pos.Y);
1525

1526
  /* Too many argument are ignored */
1527
  cursor_pos.X = 1;
1528
  cursor_pos.Y = 1;
1529
  set_cursor_position(&tty_out, cursor_pos);
1530
  capture_screen(&tty_out, &expect);
1531
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1532
  snprintf(buffer,
1533
           sizeof(buffer),
1534
           "%s%d;%d;%d;%d;%dm%s%sm",
1535
           CSI,
1536
           F_RED,
1537
           F_INTENSITY,
1538
           INVERSE,
1539
           B_CYAN,
1540
           B_INTENSITY_OFF,
1541
           HELLO,
1542
           CSI);
1543
  write_console(&tty_out, buffer);
1544
  capture_screen(&tty_out, &actual);
1545
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1546

1547
  /* In the case of DECSCUSR, the others are ignored */
1548
  set_cursor_to_home(&tty_out);
1549
  snprintf(buffer,
1550
           sizeof(buffer),
1551
           "%s%d;%d H",
1552
           CSI,
1553
           expect.si.height / 2,
1554
           expect.si.width / 2);
1555
  write_console(&tty_out, buffer);
1556
  get_cursor_position(&tty_out, &cursor_pos);
1557
  ASSERT_EQ(1, cursor_pos.X);
1558
  ASSERT_EQ(1, cursor_pos.Y);
1559

1560
  /* Invalid sequence are ignored */
1561
  saved_cursor_size = get_cursor_size(&tty_out);
1562
  set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE);
1563
  snprintf(buffer, sizeof(buffer), "%s 1q", CSI);
1564
  write_console(&tty_out, buffer);
1565
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE);
1566
  snprintf(buffer, sizeof(buffer), "%s 1 q", CSI);
1567
  write_console(&tty_out, buffer);
1568
  ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE);
1569
  set_cursor_size(&tty_out, saved_cursor_size);
1570

1571
  /* #1874 2. */
1572
  snprintf(buffer, sizeof(buffer), "%s??25l", CSI);
1573
  write_console(&tty_out, buffer);
1574
  ASSERT(get_cursor_visibility(&tty_out));
1575
  snprintf(buffer, sizeof(buffer), "%s25?l", CSI);
1576
  write_console(&tty_out, buffer);
1577
  ASSERT(get_cursor_visibility(&tty_out));
1578
  cursor_pos_old.X = expect.si.width / 2;
1579
  cursor_pos_old.Y = expect.si.height / 2;
1580
  set_cursor_position(&tty_out, cursor_pos_old);
1581
  snprintf(buffer,
1582
           sizeof(buffer),
1583
           "%s??%d;%df",
1584
           CSI,
1585
           expect.si.height / 4,
1586
           expect.si.width / 4);
1587
  write_console(&tty_out, buffer);
1588
  get_cursor_position(&tty_out, &cursor_pos);
1589
  ASSERT(cursor_pos.X = cursor_pos_old.X);
1590
  ASSERT(cursor_pos.Y = cursor_pos_old.Y);
1591
  set_cursor_to_home(&tty_out);
1592

1593
  /* CSI 25 l does nothing (#1874 4.) */
1594
  snprintf(buffer, sizeof(buffer), "%s25l", CSI);
1595
  write_console(&tty_out, buffer);
1596
  ASSERT(get_cursor_visibility(&tty_out));
1597

1598
  /* Unsupported sequences are ignored(#1874 5.) */
1599
  dir = 2;
1600
  setup_screen(&tty_out);
1601
  capture_screen(&tty_out, &expect);
1602
  set_cursor_position(&tty_out, cursor_pos);
1603
  snprintf(buffer, sizeof(buffer), "%s?%dJ", CSI, dir);
1604
  write_console(&tty_out, buffer);
1605
  capture_screen(&tty_out, &actual);
1606
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1607

1608
  /* Finally byte immedately after CSI [ are also output(#1874 1.) */
1609
  cursor_pos.X = expect.si.width / 2;
1610
  cursor_pos.Y = expect.si.height / 2;
1611
  set_cursor_position(&tty_out, cursor_pos);
1612
  capture_screen(&tty_out, &expect);
1613
  make_expect_screen_write(&expect, cursor_pos, HELLO);
1614
  snprintf(buffer, sizeof(buffer), "%s[%s", CSI, HELLO);
1615
  write_console(&tty_out, buffer);
1616
  capture_screen(&tty_out, &actual);
1617
  ASSERT(compare_screen(&tty_out, &actual, &expect));
1618

1619
  terminate_tty(&tty_out);
1620

1621
  uv_run(loop, UV_RUN_DEFAULT);
1622

1623
  MAKE_VALGRIND_HAPPY(loop);
1624
  return 0;
1625
#endif
1626
}
1627

1628
#else
1629

1630
typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
1631

1632
#endif  /* ifdef _WIN32 */
1633

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.