/* Copyright libuv project contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifdef _WIN32 #include "task.h" #include "uv.h" #include #include #include #include #define ESC "\033" #define CSI ESC "[" #define ST ESC "\\" #define BEL "\x07" #define HELLO "Hello" #define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_BLACK 0 #define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN) #define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE) #define BACKGROUND_WHITE (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_BLACK 0 #define BACKGROUND_YELLOW (BACKGROUND_RED | BACKGROUND_GREEN) #define BACKGROUND_CYAN (BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_MAGENTA (BACKGROUND_RED | BACKGROUND_BLUE) #define F_INTENSITY 1 #define FB_INTENSITY 2 #define B_INTENSITY 5 #define INVERSE 7 #define F_INTENSITY_OFF1 21 #define F_INTENSITY_OFF2 22 #define B_INTENSITY_OFF 25 #define INVERSE_OFF 27 #define F_BLACK 30 #define F_RED 31 #define F_GREEN 32 #define F_YELLOW 33 #define F_BLUE 34 #define F_MAGENTA 35 #define F_CYAN 36 #define F_WHITE 37 #define F_DEFAULT 39 #define B_BLACK 40 #define B_RED 41 #define B_GREEN 42 #define B_YELLOW 43 #define B_BLUE 44 #define B_MAGENTA 45 #define B_CYAN 46 #define B_WHITE 47 #define B_DEFAULT 49 #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_MIDDLE 50 #define CURSOR_SIZE_LARGE 100 struct screen_info { CONSOLE_SCREEN_BUFFER_INFO csbi; int top; int width; int height; int length; WORD default_attr; }; struct captured_screen { char* text; WORD* attributes; struct screen_info si; }; static void get_screen_info(uv_tty_t* tty_out, struct screen_info* si) { ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &(si->csbi))); si->width = si->csbi.dwSize.X; si->height = si->csbi.srWindow.Bottom - si->csbi.srWindow.Top + 1; si->length = si->width * si->height; si->default_attr = si->csbi.wAttributes; si->top = si->csbi.srWindow.Top; } static void set_cursor_position(uv_tty_t* tty_out, COORD pos) { HANDLE handle = tty_out->handle; CONSOLE_SCREEN_BUFFER_INFO info; ASSERT(GetConsoleScreenBufferInfo(handle, &info)); pos.X -= 1; pos.Y += info.srWindow.Top - 1; ASSERT(SetConsoleCursorPosition(handle, pos)); } static void get_cursor_position(uv_tty_t* tty_out, COORD* cursor_position) { HANDLE handle = tty_out->handle; CONSOLE_SCREEN_BUFFER_INFO info; ASSERT(GetConsoleScreenBufferInfo(handle, &info)); cursor_position->X = info.dwCursorPosition.X + 1; cursor_position->Y = info.dwCursorPosition.Y - info.srWindow.Top + 1; } static void set_cursor_to_home(uv_tty_t* tty_out) { COORD origin = {1, 1}; set_cursor_position(tty_out, origin); } static CONSOLE_CURSOR_INFO get_cursor_info(uv_tty_t* tty_out) { HANDLE handle = tty_out->handle; CONSOLE_CURSOR_INFO info; ASSERT(GetConsoleCursorInfo(handle, &info)); return info; } static void set_cursor_size(uv_tty_t* tty_out, DWORD size) { CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); info.dwSize = size; ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); } static DWORD get_cursor_size(uv_tty_t* tty_out) { return get_cursor_info(tty_out).dwSize; } static void set_cursor_visibility(uv_tty_t* tty_out, BOOL visible) { CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); info.bVisible = visible; ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); } static BOOL get_cursor_visibility(uv_tty_t* tty_out) { return get_cursor_info(tty_out).bVisible; } static BOOL is_scrolling(uv_tty_t* tty_out, struct screen_info si) { CONSOLE_SCREEN_BUFFER_INFO info; ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); return info.srWindow.Top != si.top; } static void write_console(uv_tty_t* tty_out, char* src) { int r; uv_buf_t buf; buf.base = src; buf.len = strlen(buf.base); r = uv_try_write((uv_stream_t*) tty_out, &buf, 1); ASSERT(r >= 0); ASSERT((unsigned int) r == buf.len); } static void setup_screen(uv_tty_t* tty_out) { DWORD length, number_of_written; COORD origin; CONSOLE_SCREEN_BUFFER_INFO info; ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); length = info.dwSize.X * (info.srWindow.Bottom - info.srWindow.Top + 1); origin.X = 0; origin.Y = info.srWindow.Top; ASSERT(FillConsoleOutputCharacter( tty_out->handle, '.', length, origin, &number_of_written)); ASSERT(length == number_of_written); } static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) { DWORD length, number_of_written; COORD origin; CONSOLE_SCREEN_BUFFER_INFO info; ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); length = (info.srWindow.Bottom - info.srWindow.Top + 1) * info.dwSize.X - 1; origin.X = 0; origin.Y = info.srWindow.Top; FillConsoleOutputCharacterA( tty_out->handle, ' ', length, origin, &number_of_written); ASSERT(length == number_of_written); FillConsoleOutputAttribute( tty_out->handle, si->default_attr, length, origin, &number_of_written); ASSERT(length == number_of_written); } static void free_screen(struct captured_screen* cs) { free(cs->text); cs->text = NULL; free(cs->attributes); cs->attributes = NULL; } static void capture_screen(uv_tty_t* tty_out, struct captured_screen* cs) { DWORD length; COORD origin; get_screen_info(tty_out, &(cs->si)); origin.X = 0; origin.Y = cs->si.csbi.srWindow.Top; cs->text = malloc(cs->si.length * sizeof(*cs->text)); ASSERT(cs->text != NULL); cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes)); ASSERT(cs->attributes != NULL); ASSERT(ReadConsoleOutputCharacter( tty_out->handle, cs->text, cs->si.length, origin, &length)); ASSERT((unsigned int) cs->si.length == length); ASSERT(ReadConsoleOutputAttribute( tty_out->handle, cs->attributes, cs->si.length, origin, &length)); ASSERT((unsigned int) cs->si.length == length); } static void make_expect_screen_erase(struct captured_screen* cs, COORD cursor_position, int dir, BOOL entire_screen) { /* beginning of line */ char* start; char* end; start = cs->text + cs->si.width * (cursor_position.Y - 1); if (dir == 0) { if (entire_screen) { /* erase to end of screen */ end = cs->text + cs->si.length; } else { /* erase to end of line */ end = start + cs->si.width; } /* erase from postition of cursor */ start += cursor_position.X - 1; } else if (dir == 1) { /* erase to position of cursor */ end = start + cursor_position.X; if (entire_screen) { /* erase form beginning of screen */ start = cs->text; } } else if (dir == 2) { if (entire_screen) { /* erase form beginning of screen */ start = cs->text; /* erase to end of screen */ end = cs->text + cs->si.length; } else { /* erase to end of line */ end = start + cs->si.width; } } else { ASSERT(FALSE); } ASSERT(start < end); ASSERT(end - cs->text <= cs->si.length); for (; start < end; start++) { *start = ' '; } } static void make_expect_screen_write(struct captured_screen* cs, COORD cursor_position, const char* text) { /* postion of cursor */ char* start; start = cs->text + cs->si.width * (cursor_position.Y - 1) + cursor_position.X - 1; size_t length = strlen(text); size_t remain_length = cs->si.length - (cs->text - start); length = length > remain_length ? remain_length : length; memcpy(start, text, length); } static void make_expect_screen_set_attr(struct captured_screen* cs, COORD cursor_position, size_t length, WORD attr) { WORD* start; start = cs->attributes + cs->si.width * (cursor_position.Y - 1) + cursor_position.X - 1; size_t remain_length = cs->si.length - (cs->attributes - start); length = length > remain_length ? remain_length : length; while (length) { *start = attr; start++; length--; } } static BOOL compare_screen(uv_tty_t* tty_out, struct captured_screen* actual, struct captured_screen* expect) { int line, col; BOOL result = TRUE; int current = 0; ASSERT(actual->text); ASSERT(actual->attributes); ASSERT(expect->text); ASSERT(expect->attributes); if (actual->si.length != expect->si.length) { return FALSE; } if (actual->si.width != expect->si.width) { return FALSE; } if (actual->si.height != expect->si.height) { return FALSE; } while (current < actual->si.length) { if (*(actual->text + current) != *(expect->text + current)) { line = current / actual->si.width + 1; col = current - actual->si.width * (line - 1) + 1; fprintf(stderr, "line:%d col:%d expected character '%c' but found '%c'\n", line, col, *(expect->text + current), *(actual->text + current)); result = FALSE; } if (*(actual->attributes + current) != *(expect->attributes + current)) { line = current / actual->si.width + 1; col = current - actual->si.width * (line - 1) + 1; fprintf(stderr, "line:%d col:%d expected attributes '%u' but found '%u'\n", line, col, *(expect->attributes + current), *(actual->attributes + current)); result = FALSE; } current++; } clear_screen(tty_out, &expect->si); free_screen(expect); free_screen(actual); return result; } static void initialize_tty(uv_tty_t* tty_out) { int r; int ttyout_fd; /* Make sure we have an FD that refers to a tty */ HANDLE handle; uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED); handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); ASSERT(handle != INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT(ttyout_fd >= 0); ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); r = uv_tty_init(uv_default_loop(), tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); } static void terminate_tty(uv_tty_t* tty_out) { set_cursor_to_home(tty_out); uv_close((uv_handle_t*) tty_out, NULL); } TEST_IMPL(tty_cursor_up) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor up one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sA", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor up nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dA", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor up from Window top does nothing */ cursor_pos_old.X = 1; cursor_pos_old.Y = 1; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sA", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_down) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor down one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sB", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor down nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dB", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor down from bottom line does nothing */ cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sB", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_forward) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor forward one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X + 1 == cursor_pos.X); /* cursor forward nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dC", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X + si.width / 4 == cursor_pos.X); /* cursor forward from end of line does nothing*/ cursor_pos_old.X = si.width; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor forward from end of screen does nothing */ cursor_pos_old.X = si.width; cursor_pos_old.Y = si.height; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_back) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor back one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X - 1 == cursor_pos.X); /* cursor back nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dD", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X - si.width / 4 == cursor_pos.X); /* cursor back from beginning of line does nothing */ cursor_pos_old.X = 1; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(cursor_pos_old.X == cursor_pos.X); /* cursor back from top of screen does nothing */ cursor_pos_old.X = 1; cursor_pos_old.Y = 1; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(1 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_next_line) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor next line one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sE", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); /* cursor next line nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dE", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); /* cursor next line from buttom row moves beginning of line */ cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sE", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y == cursor_pos.Y); ASSERT(1 == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_previous_line) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* cursor previous line one times if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sF", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); /* cursor previous line nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dF", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); /* cursor previous line from top of screen does nothing */ cursor_pos_old.X = 1; cursor_pos_old.Y = 1; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(1 == cursor_pos.Y); ASSERT(1 == cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_horizontal_move_absolute) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* Move to beginning of line if omitted argument */ snprintf(buffer, sizeof(buffer), "%sG", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(1 == cursor_pos.X); ASSERT(cursor_pos_old.Y == cursor_pos.Y); /* Move cursor to nth character */ snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(si.width / 4 == cursor_pos.X); ASSERT(cursor_pos_old.Y == cursor_pos.Y); /* Moving out of screen will fit within screen */ snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(si.width == cursor_pos.X); ASSERT(cursor_pos_old.Y == cursor_pos.Y); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_cursor_move_absolute) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos.X = si.width / 2; cursor_pos.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos); /* Move the cursor to home if omitted arguments */ snprintf(buffer, sizeof(buffer), "%sH", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(1 == cursor_pos.X); ASSERT(1 == cursor_pos.Y); /* Move the cursor to the middle of the screen */ snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(si.width / 2 == cursor_pos.X); ASSERT(si.height / 2 == cursor_pos.Y); /* Moving out of screen will fit within screen */ snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(si.width == cursor_pos.X); ASSERT(si.height / 2 == cursor_pos.Y); snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height + 1, si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(si.width / 2 == cursor_pos.X); ASSERT(si.height == cursor_pos.Y); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_hide_show_cursor) { uv_tty_t tty_out; uv_loop_t* loop; char buffer[1024]; BOOL saved_cursor_visibility; loop = uv_default_loop(); initialize_tty(&tty_out); saved_cursor_visibility = get_cursor_visibility(&tty_out); /* Hide the cursor */ set_cursor_visibility(&tty_out, TRUE); snprintf(buffer, sizeof(buffer), "%s?25l", CSI); write_console(&tty_out, buffer); ASSERT(!get_cursor_visibility(&tty_out)); /* Show the cursor */ set_cursor_visibility(&tty_out, FALSE); snprintf(buffer, sizeof(buffer), "%s?25h", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_visibility(&tty_out)); set_cursor_visibility(&tty_out, saved_cursor_visibility); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_erase) { int dir; uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos; char buffer[1024]; struct captured_screen actual = {0}, expect = {0}; loop = uv_default_loop(); initialize_tty(&tty_out); /* Erase to below if omitted argument */ dir = 0; setup_screen(&tty_out); capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%sJ", CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase to below(dir = 0) */ setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase to above */ dir = 1; setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase All */ dir = 2; setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_erase_line) { int dir; uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos; char buffer[1024]; struct captured_screen actual = {0}, expect = {0}; loop = uv_default_loop(); initialize_tty(&tty_out); /* Erase to right if omitted arguments */ dir = 0; setup_screen(&tty_out); capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%sK", CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase to right(dir = 0) */ setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase to Left */ dir = 1; setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Erase All */ dir = 2; setup_screen(&tty_out); capture_screen(&tty_out, &expect); make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_set_cursor_shape) { uv_tty_t tty_out; uv_loop_t* loop; DWORD saved_cursor_size; char buffer[1024]; loop = uv_default_loop(); initialize_tty(&tty_out); saved_cursor_size = get_cursor_size(&tty_out); /* cursor size large if omitted arguments */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); /* cursor size large */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s1 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s2 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); /* cursor size small */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s3 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s6 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); /* Nothing occurs with arguments outside valid range */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s7 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); /* restore cursor size if arguments is zero */ snprintf(buffer, sizeof(buffer), "%s0 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_set_style) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos; char buffer[1024]; struct captured_screen actual = {0}, expect = {0}; WORD fg, bg; WORD fg_attrs[9][2] = {{F_BLACK, FOREGROUND_BLACK}, {F_RED, FOREGROUND_RED}, {F_GREEN, FOREGROUND_GREEN}, {F_YELLOW, FOREGROUND_YELLOW}, {F_BLUE, FOREGROUND_BLUE}, {F_MAGENTA, FOREGROUND_MAGENTA}, {F_CYAN, FOREGROUND_CYAN}, {F_WHITE, FOREGROUND_WHITE}, {F_DEFAULT, 0}}; WORD bg_attrs[9][2] = {{B_DEFAULT, 0}, {B_BLACK, BACKGROUND_BLACK}, {B_RED, BACKGROUND_RED}, {B_GREEN, BACKGROUND_GREEN}, {B_YELLOW, BACKGROUND_YELLOW}, {B_BLUE, BACKGROUND_BLUE}, {B_MAGENTA, BACKGROUND_MAGENTA}, {B_CYAN, BACKGROUND_CYAN}, {B_WHITE, BACKGROUND_WHITE}}; WORD attr; int i, length; loop = uv_default_loop(); initialize_tty(&tty_out); capture_screen(&tty_out, &expect); fg_attrs[8][1] = expect.si.default_attr & FOREGROUND_WHITE; bg_attrs[0][1] = expect.si.default_attr & BACKGROUND_WHITE; /* Set foreground color */ length = ARRAY_SIZE(fg_attrs); for (i = 0; i < length; i++) { capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; attr = (expect.si.default_attr & ~FOREGROUND_WHITE) | fg_attrs[i][1]; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); set_cursor_position(&tty_out, cursor_pos); snprintf( buffer, sizeof(buffer), "%s%dm%s%sm", CSI, fg_attrs[i][0], HELLO, CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); } /* Set background color */ length = ARRAY_SIZE(bg_attrs); for (i = 0; i < length; i++) { capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; attr = (expect.si.default_attr & ~BACKGROUND_WHITE) | bg_attrs[i][1]; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); set_cursor_position(&tty_out, cursor_pos); snprintf( buffer, sizeof(buffer), "%s%dm%s%sm", CSI, bg_attrs[i][0], HELLO, CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); } /* Set foregroud and background color */ ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs)); length = ARRAY_SIZE(bg_attrs); for (i = 0; i < length; i++) { capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; attr = expect.si.default_attr & ~FOREGROUND_WHITE & ~BACKGROUND_WHITE; attr |= fg_attrs[i][1] | bg_attrs[i][1]; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%d;%dm%s%sm", CSI, bg_attrs[i][0], fg_attrs[i][0], HELLO, CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); } /* Set foreground bright on */ capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos); attr = expect.si.default_attr; attr |= FOREGROUND_INTENSITY; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); snprintf(buffer, sizeof(buffer), "%s%dm%s%s%dm%s%dm%s%s%dm", CSI, F_INTENSITY, HELLO, CSI, F_INTENSITY_OFF1, CSI, F_INTENSITY, HELLO, CSI, F_INTENSITY_OFF2); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Set background bright on */ capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos); attr = expect.si.default_attr; attr |= BACKGROUND_INTENSITY; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); snprintf(buffer, sizeof(buffer), "%s%dm%s%s%dm", CSI, B_INTENSITY, HELLO, CSI, B_INTENSITY_OFF); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Inverse */ capture_screen(&tty_out, &expect); cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos); attr = expect.si.default_attr; fg = attr & FOREGROUND_WHITE; bg = attr & BACKGROUND_WHITE; attr &= (~FOREGROUND_WHITE & ~BACKGROUND_WHITE); attr |= COMMON_LVB_REVERSE_VIDEO; attr |= fg << 4; attr |= bg >> 4; make_expect_screen_write(&expect, cursor_pos, HELLO); make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s%dm%s%s%dm%s", CSI, INVERSE, HELLO, CSI, INVERSE_OFF, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_save_restore_cursor_position) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; char buffer[1024]; struct screen_info si; loop = uv_default_loop(); initialize_tty(&tty_out); get_screen_info(&tty_out, &si); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* save the cursor position */ snprintf(buffer, sizeof(buffer), "%ss", CSI); write_console(&tty_out, buffer); cursor_pos.X = si.width / 4; cursor_pos.Y = si.height / 4; set_cursor_position(&tty_out, cursor_pos); /* restore the cursor postion */ snprintf(buffer, sizeof(buffer), "%su", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos.X == cursor_pos_old.X); ASSERT(cursor_pos.Y == cursor_pos_old.Y); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); /* save the cursor position */ snprintf(buffer, sizeof(buffer), "%s7", ESC); write_console(&tty_out, buffer); cursor_pos.X = si.width / 4; cursor_pos.Y = si.height / 4; set_cursor_position(&tty_out, cursor_pos); /* restore the cursor postion */ snprintf(buffer, sizeof(buffer), "%s8", ESC); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos.X == cursor_pos_old.X); ASSERT(cursor_pos.Y == cursor_pos_old.Y); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_full_reset) { uv_tty_t tty_out; uv_loop_t* loop; char buffer[1024]; struct captured_screen actual = {0}, expect = {0}; COORD cursor_pos; DWORD saved_cursor_size; BOOL saved_cursor_visibility; loop = uv_default_loop(); initialize_tty(&tty_out); capture_screen(&tty_out, &expect); setup_screen(&tty_out); cursor_pos.X = expect.si.width; cursor_pos.Y = expect.si.height; set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO); saved_cursor_size = get_cursor_size(&tty_out); set_cursor_size(&tty_out, saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL : CURSOR_SIZE_LARGE); saved_cursor_visibility = get_cursor_visibility(&tty_out); set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE); write_console(&tty_out, buffer); snprintf(buffer, sizeof(buffer), "%sc", ESC); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); ASSERT(get_cursor_visibility(&tty_out) == saved_cursor_visibility); ASSERT(actual.si.csbi.srWindow.Top == 0); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } TEST_IMPL(tty_escape_sequence_processing) { uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; DWORD saved_cursor_size; char buffer[1024]; struct captured_screen actual = {0}, expect = {0}; int dir; loop = uv_default_loop(); initialize_tty(&tty_out); /* CSI + finaly byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s@%s%s~%s", CSI, HELLO, CSI, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* CSI(C1) + finaly byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "\xC2\x9B@%s\xC2\x9B~%s", HELLO, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* CSI + intermediate byte + finaly byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* CSI + parameter byte + finaly byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); snprintf(buffer, sizeof(buffer), "%s0@%s%s>~%s%s?~%s", CSI, HELLO, CSI, HELLO, CSI, HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* ESC Single-char control does not output anyghing */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Nothing is output from ESC + ^, _, P, ] to BEL or ESC \ */ /* Operaging System Command */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s]0;%s%s%s", ESC, HELLO, BEL, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Device Control Sequence */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%sP$m%s%s", ESC, ST, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Privacy Message */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s^\"%s\\\"%s\"%s%s", ESC, HELLO, HELLO, ST, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Application Program Command */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s_\"%s%s%s\"%s%s", ESC, HELLO, ST, HELLO, BEL, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Ignore double escape */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); cursor_pos.X += strlen(HELLO); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s%s@%s%s%s~%s", ESC, CSI, HELLO, ESC, CSI, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Ignored if argument overflow */ set_cursor_to_home(&tty_out); snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos.X == 1); ASSERT(cursor_pos.Y == 1); /* Too many argument are ignored */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s%d;%d;%d;%d;%dm%s%sm", CSI, F_RED, F_INTENSITY, INVERSE, B_CYAN, B_INTENSITY_OFF, HELLO, CSI); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* In the case of DECSCUSR, the others are ignored */ set_cursor_to_home(&tty_out); snprintf(buffer, sizeof(buffer), "%s%d;%d H", CSI, expect.si.height / 2, expect.si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos.X == 1); ASSERT(cursor_pos.Y == 1); /* Invalid sequence are ignored */ saved_cursor_size = get_cursor_size(&tty_out); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s 1q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s 1 q", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); set_cursor_size(&tty_out, saved_cursor_size); /* #1874 2. */ snprintf(buffer, sizeof(buffer), "%s??25l", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_visibility(&tty_out)); snprintf(buffer, sizeof(buffer), "%s25?l", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_visibility(&tty_out)); cursor_pos_old.X = expect.si.width / 2; cursor_pos_old.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos_old); snprintf(buffer, sizeof(buffer), "%s??%d;%df", CSI, expect.si.height / 4, expect.si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); ASSERT(cursor_pos.X = cursor_pos_old.X); ASSERT(cursor_pos.Y = cursor_pos_old.Y); set_cursor_to_home(&tty_out); /* CSI 25 l does nothing (#1874 4.) */ snprintf(buffer, sizeof(buffer), "%s25l", CSI); write_console(&tty_out, buffer); ASSERT(get_cursor_visibility(&tty_out)); /* Unsupported sequences are ignored(#1874 5.) */ dir = 2; setup_screen(&tty_out); capture_screen(&tty_out, &expect); set_cursor_position(&tty_out, cursor_pos); snprintf(buffer, sizeof(buffer), "%s?%dJ", CSI, dir); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); /* Finaly byte immedately after CSI [ are also output(#1874 1.) */ cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos); capture_screen(&tty_out, &expect); make_expect_screen_write(&expect, cursor_pos, HELLO); snprintf(buffer, sizeof(buffer), "%s[%s", CSI, HELLO); write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); terminate_tty(&tty_out); uv_run(loop, UV_RUN_DEFAULT); MAKE_VALGRIND_HAPPY(); return 0; } #else typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ #endif /* ifdef _WIN32 */