[KERNEL32_APITEST] More power to ConsoleCP testcase (#2187)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Sun, 29 Dec 2019 04:12:39 +0000 (13:12 +0900)
committerGitHub <noreply@github.com>
Sun, 29 Dec 2019 04:12:39 +0000 (13:12 +0900)
Strengthen kernel32_apitest ConsoleCP testcase for COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE attributes. CORE-12451

modules/rostests/apitests/kernel32/ConsoleCP.c

index 3a38197..315f182 100644 (file)
 #define ATTR \
     (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
 
-static const WCHAR u0414[] = { 0x0414, 0 };             /* Д */
-static const WCHAR u9580[] = { 0x9580, 0 };             /* 門 */
-static const WCHAR ideograph_space = (WCHAR)0x3000;     /* fullwidth space */
+static const WCHAR u0414[] = {0x0414, 0}; /* Д */
+static const WCHAR u9580[] = {0x9580, 0}; /* 門 */
+static const WCHAR space[] = {L' ', 0};
+static const WCHAR ideograph_space = (WCHAR)0x3000; /* fullwidth space */
 static LCID lcidJapanese = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT);
 static LCID lcidRussian  = MAKELCID(MAKELANGID(LANG_RUSSIAN , SUBLANG_DEFAULT), SORT_DEFAULT);
 static BOOL s_bIs8Plus;
@@ -73,8 +74,7 @@ static void test_cp855(HANDLE hConOut)
     ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
     ok(ret, "GetConsoleScreenBufferInfo failed\n");
     trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
-    count = csbi.dwSize.X * 3 / 2;
-    trace("count: %d\n", count);
+    count = 200;
 
     /* "\u0414" */
     {
@@ -263,11 +263,13 @@ static void test_cp932(HANDLE hConOut)
     DWORD oldcp;
     int n;
     DWORD len;
-    COORD c;
+    COORD c, buffSize;
     CONSOLE_SCREEN_BUFFER_INFO csbi;
     int count;
     WCHAR str[32];
-    WORD attr;
+    WORD attr, attrs[4];
+    CHAR_INFO buff[16];
+    SMALL_RECT sr;
 
     if (!IsValidCodePage(932))
     {
@@ -289,8 +291,7 @@ static void test_cp932(HANDLE hConOut)
     ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
     ok(ret, "GetConsoleScreenBufferInfo failed\n");
     trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
-    count = csbi.dwSize.X * 3 / 2;
-    trace("count: %d\n", count);
+    count = 200;
 
     /* "\u0414" */
     {
@@ -470,6 +471,625 @@ static void test_cp932(HANDLE hConOut)
         }
     }
 
+    /* COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE for u0414 */
+    {
+        /* set cursor */
+        c.X = c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* fill by 'A' */
+        ret = FillConsoleOutputCharacterW(hConOut, L'A', csbi.dwSize.X * 2, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, csbi.dwSize.X * 2);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, L'A');
+        ok_int(buff[0].Attributes, ATTR);
+
+        /* read attr */
+        ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
+        ok_int(ret, 1);
+        ok_int(attr, ATTR);
+        ok_long(len, 1);
+
+        /* read char */
+        c.X = c.Y = 0;
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], L'A');
+        ok_int(str[1], L'A');
+        ok_int(str[2], L'A');
+        ok_int(str[3], L'A');
+
+        /* set cursor */
+        c.X = c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u0414 */
+        ret = WriteConsoleW(hConOut, u0414, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x0414);
+            ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[1].Char.UnicodeChar, 0x0414);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x0414);
+            ok_int(buff[0].Attributes, ATTR);
+            ok_int(buff[1].Char.UnicodeChar, L'A');
+            ok_int(buff[1].Attributes, ATTR);
+        }
+        ok_int(buff[2].Char.UnicodeChar, L'A');
+        ok_int(buff[2].Attributes, ATTR);
+        ok_int(buff[3].Char.UnicodeChar, L'A');
+        ok_int(buff[3].Attributes, ATTR);
+
+        /* read attr */
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
+        ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
+        ok_int(attrs[2], ATTR);
+        ok_int(attrs[3], ATTR);
+
+        /* read char */
+        c.X = c.Y = 0;
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], 0x0414);
+        ok_int(str[1], L'A');
+        ok_int(str[2], L'A');
+        if (s_bIs8Plus)
+            ok_int(str[3], 0);
+        else
+            ok_int(str[3], 0x7F7F);
+
+        /* set cursor */
+        c.X = 1;
+        c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u0414 */
+        ret = WriteConsoleW(hConOut, u0414, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x0414);
+            ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[1].Char.UnicodeChar, 0x0414);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[2].Char.UnicodeChar, 0x0414);
+            ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[0].Char.UnicodeChar, L' ');
+            ok_int(buff[0].Attributes, ATTR);
+            ok_int(buff[1].Char.UnicodeChar, 0x0414);
+            ok_int(buff[1].Attributes, ATTR);
+            ok_int(buff[2].Char.UnicodeChar, L'A');
+            ok_int(buff[2].Attributes, ATTR);
+        }
+        ok_int(buff[3].Char.UnicodeChar, L'A');
+        ok_int(buff[3].Attributes, ATTR);
+
+        /* read attr */
+        c.X = c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        if (s_bIs8Plus)
+            ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
+        else
+            ok_int(attrs[0], ATTR);
+        ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
+        ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
+        ok_int(attrs[3], ATTR);
+
+        /* read char */
+        c.X = c.Y = 0;
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
+        ok_int(ret, 1);
+        if (s_bIs8Plus)
+        {
+            ok_int(str[0], 0x0414);
+            ok_int(str[1], 0x0414);
+            ok_int(str[2], L'A');
+            ok_int(str[3], 0);
+        }
+        else
+        {
+            ok_int(str[0], L' ');
+            ok_int(str[1], 0x0414);
+            ok_int(str[2], L'A');
+            ok_int(str[3], 0x7F7F);
+        }
+
+        /* set cursor */
+        c.X = csbi.dwSize.X - 1;
+        c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u0414 */
+        WriteConsoleW(hConOut, u0414, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        sr.Left = csbi.dwSize.X - 2;
+        sr.Top = 0;
+        sr.Right = csbi.dwSize.X - 1;
+        sr.Bottom = 0;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, csbi.dwSize.X - 2);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, csbi.dwSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, L'A');
+        ok_int(buff[0].Attributes, ATTR);
+        ok_int(buff[1].Char.UnicodeChar, L'A');
+        ok_int(buff[1].Attributes, ATTR);
+
+        /* read attrs */
+        c.X = csbi.dwSize.X - 2;
+        c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        ok_int(attrs[0], ATTR);
+        ok_int(attrs[1], ATTR);
+
+        /* read char */
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], L'A');
+        ok_int(str[1], L'A');
+
+        /* fill by 'A' */
+        c.X = c.Y = 0;
+        ret = FillConsoleOutputCharacterW(hConOut, L'A', 10, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, 10);
+
+        /* fill by u0414 */
+        c.X = 1;
+        c.Y = 0;
+        ret = FillConsoleOutputCharacterW(hConOut, 0x0414, 1, c, &len);
+        c.X = c.Y = 0;
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        sr.Left = 0;
+        sr.Top = 0;
+        sr.Right = 4;
+        sr.Bottom = 0;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, 4);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, 'A');
+        ok_int(buff[0].Attributes, ATTR);
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[1].Char.UnicodeChar, 0x0414);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[2].Char.UnicodeChar, 0x0414);
+            ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[1].Char.UnicodeChar, L' ');
+            ok_int(buff[1].Attributes, ATTR);
+            ok_int(buff[2].Char.UnicodeChar, 'A');
+            ok_int(buff[2].Attributes, ATTR);
+        }
+        ok_int(buff[3].Char.UnicodeChar, 'A');
+        ok_int(buff[3].Attributes, ATTR);
+        ok_int(buff[4].Char.UnicodeChar, 'A');
+        ok_int(buff[4].Attributes, ATTR);
+
+        /* read attrs */
+        c.X = 0;
+        c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        ok_int(attrs[0], ATTR);
+        if (s_bIs8Plus)
+        {
+            ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(attrs[1], ATTR);
+            ok_int(attrs[2], ATTR);
+        }
+        ok_int(attrs[3], ATTR);
+    }
+
+    /* COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE for u9580 */
+    {
+        /* set cursor */
+        c.X = c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* fill by 'A' */
+        ret = FillConsoleOutputCharacterW(hConOut, L'A', csbi.dwSize.X * 2, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, csbi.dwSize.X * 2);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, L'A');
+        ok_int(buff[0].Attributes, ATTR);
+
+        /* read attr */
+        ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
+        ok_int(ret, 1);
+        ok_int(attr, ATTR);
+        ok_long(len, 1);
+
+        /* read char */
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], L'A');
+        ok_int(str[1], L'A');
+
+        /* set cursor */
+        c.X = 0;
+        c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u9580 */
+        ret = WriteConsoleW(hConOut, u9580, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x9580);
+            ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[1].Char.UnicodeChar, 0x9580);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x9580);
+            ok_int(buff[0].Attributes, ATTR);
+            ok_int(buff[1].Char.UnicodeChar, L'A');
+            ok_int(buff[1].Attributes, ATTR);
+        }
+        ok_int(buff[2].Char.UnicodeChar, L'A');
+        ok_int(buff[2].Attributes, ATTR);
+        ok_int(buff[3].Char.UnicodeChar, L'A');
+        ok_int(buff[3].Attributes, ATTR);
+
+        /* read attr */
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+
+        ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
+        ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
+        ok_int(attrs[2], ATTR);
+        ok_int(attrs[3], ATTR);
+
+        /* read char */
+        c.X = c.Y = 0;
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], 0x9580);
+        ok_int(str[1], L'A');
+        ok_int(str[2], L'A');
+        if (s_bIs8Plus)
+            ok_int(str[3], 0);
+        else
+            ok_int(str[3], 0x7F7F);
+
+        /* set cursor */
+        c.X = 1;
+        c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u9580 */
+        ret = WriteConsoleW(hConOut, u9580, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* read output */
+        c.X = c.Y = 0;
+        ZeroMemory(&sr, sizeof(sr));
+        sr.Right = buffSize.X - 1;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, buffSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[0].Char.UnicodeChar, 0x9580);
+            ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[1].Char.UnicodeChar, 0x9580);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[2].Char.UnicodeChar, 0x9580);
+            ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[0].Char.UnicodeChar, L' ');
+            ok_int(buff[0].Attributes, ATTR);
+            ok_int(buff[1].Char.UnicodeChar, 0x9580);
+            ok_int(buff[1].Attributes, ATTR);
+            ok_int(buff[2].Char.UnicodeChar, L'A');
+            ok_int(buff[2].Attributes, ATTR);
+        }
+        ok_int(buff[3].Char.UnicodeChar, L'A');
+        ok_int(buff[3].Attributes, ATTR);
+
+        /* read attr */
+        c.X = c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+
+        if (s_bIs8Plus)
+        {
+            ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
+        }
+        else
+        {
+            ok_int(attrs[0], ATTR);
+        }
+        ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
+        ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
+        ok_int(attrs[3], ATTR);
+
+        /* set cursor */
+        c.X = csbi.dwSize.X - 1;
+        c.Y = 0;
+        SetConsoleCursorPosition(hConOut, c);
+        okCURSOR(hConOut, c);
+
+        /* write u9580 */
+        WriteConsoleW(hConOut, u9580, 1, &len, NULL);
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        sr.Left = csbi.dwSize.X - 2;
+        sr.Top = 0;
+        sr.Right = csbi.dwSize.X - 1;
+        sr.Bottom = 0;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, csbi.dwSize.X - 2);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, csbi.dwSize.X - 1);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, 'A');
+        ok_int(buff[0].Attributes, ATTR);
+        ok_int(buff[1].Char.UnicodeChar, 'A');
+        ok_int(buff[1].Attributes, ATTR);
+
+        /* read attr */
+        c.X = csbi.dwSize.X - 2;
+        c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        ok_int(attrs[0], ATTR);
+        ok_int(attrs[1], ATTR);
+
+        /* read char */
+        memset(str, 0x7F, sizeof(str));
+        ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
+        ok_int(ret, 1);
+        ok_int(str[0], L'A');
+        ok_int(str[1], L'A');
+
+        /* fill by 'A' */
+        c.X = c.Y = 0;
+        ret = FillConsoleOutputCharacterW(hConOut, L'A', 10, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, 10);
+
+        /* fill by u9580 */
+        c.X = 1;
+        c.Y = 0;
+        ret = FillConsoleOutputCharacterW(hConOut, 0x9580, 1, c, &len);
+        c.X = c.Y = 0;
+        ok_int(ret, 1);
+        ok_long(len, 1);
+
+        /* reset buff */
+        buffSize.X = ARRAYSIZE(buff);
+        buffSize.Y = 1;
+        memset(buff, 0x7F, sizeof(buff));
+
+        /* read output */
+        c.X = c.Y = 0;
+        sr.Left = 0;
+        sr.Top = 0;
+        sr.Right = 4;
+        sr.Bottom = 0;
+        ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
+        ok_int(ret, 1);
+        ok_int(sr.Left, 0);
+        ok_int(sr.Top, 0);
+        ok_int(sr.Right, 4);
+        ok_int(sr.Bottom, 0);
+
+        /* check buff */
+        ok_int(buff[0].Char.UnicodeChar, 'A');
+        ok_int(buff[0].Attributes, ATTR);
+        if (s_bIs8Plus)
+        {
+            ok_int(buff[1].Char.UnicodeChar, 0x9580);
+            ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(buff[2].Char.UnicodeChar, 0x9580);
+            ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(buff[1].Char.UnicodeChar, L' ');
+            ok_int(buff[1].Attributes, ATTR);
+            ok_int(buff[2].Char.UnicodeChar, 'A');
+            ok_int(buff[2].Attributes, ATTR);
+        }
+        ok_int(buff[3].Char.UnicodeChar, 'A');
+        ok_int(buff[3].Attributes, ATTR);
+        ok_int(buff[4].Char.UnicodeChar, 'A');
+        ok_int(buff[4].Attributes, ATTR);
+
+        /* read attrs */
+        c.X = 0;
+        c.Y = 0;
+        ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
+        ok_int(ret, 1);
+        ok_long(len, ARRAYSIZE(attrs));
+        ok_int(attrs[0], ATTR);
+        if (s_bIs8Plus)
+        {
+            ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
+            ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
+        }
+        else
+        {
+            ok_int(attrs[1], ATTR);
+            ok_int(attrs[2], ATTR);
+        }
+        ok_int(attrs[3], ATTR);
+    }
+
     /* Restore code page */
     SetConsoleOutputCP(oldcp);
 }