reactos/rostests/apitests/kernel32/Console.c
Hermès Bélusca-Maïto 3849c29490 [KERNEL32_APITEST]: Internationalization console tests by Katayama Hirofumi MZ.
Passes on Win2k3 (either are skipped because either Russian or Japanese locales or codepages are absent, or are passed OK), but not on ReactOS yet. They are committed as reference for future work.
CORE-12451

svn path=/trunk/; revision=74475
2017-05-04 15:39:50 +00:00

477 lines
16 KiB
C

/*
* PROJECT: ReactOS api tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Test for i18n console test
* PROGRAMMERS: Katayama Hirofumi MZ
*/
#include <apitest.h>
#include <wincon.h>
#include <winnls.h>
#define okCURSOR(hCon, c) do { \
CONSOLE_SCREEN_BUFFER_INFO __sbi; \
BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
__sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
(c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
} while (0)
#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 */
LCID lcidJapanese = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT);
LCID lcidRussian = MAKELCID(MAKELANGID(LANG_RUSSIAN , SUBLANG_DEFAULT), SORT_DEFAULT);
/* Russian Code Page 855 */
// NOTE that CP 866 can also be used
static void test_cp855(HANDLE hConOut)
{
BOOL ret;
DWORD oldcp;
int n;
DWORD len;
COORD c;
CONSOLE_SCREEN_BUFFER_INFO csbi;
int count;
WCHAR str[32];
WORD attr;
if (!IsValidCodePage(855))
{
skip("Codepage 855 not available\n");
return;
}
/* Set code page */
oldcp = GetConsoleOutputCP();
SetLastError(0xdeadbeef);
ret = SetConsoleOutputCP(855);
if (!ret)
{
skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
return;
}
/* Get info */
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);
/* "\u0414" */
{
/* Output u0414 "count" times at (0,0) */
c.X = c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
}
/* Check cursor */
len = count; /* u0414 is normal width in Russian */
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 6, "len was: %ld\n", len);
ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
/* Check cursor */
c.X = 1;
c.Y = 0;
ret = SetConsoleCursorPosition(hConOut, c);
ok(ret, "SetConsoleCursorPosition failed\n");
okCURSOR(hConOut, c);
/* Fill by space */
c.X = c.Y = 0;
FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
/* Output u0414 "count" times at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
}
/* Check cursor */
len = 1 + count;
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 6, "len was: %ld\n", len);
ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
}
/* "\u9580" */
{
/* Output u9580 "count" times at (0,0) */
c.X = c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
}
/* Check cursor */
len = count; /* u9580 is normal width in Russian */
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Check cursor */
c.X = 1;
c.Y = 0;
ret = SetConsoleCursorPosition(hConOut, c);
ok(ret, "SetConsoleCursorPosition failed\n");
okCURSOR(hConOut, c);
/* Fill by space */
c.X = c.Y = 0;
ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
ok(ret, "FillConsoleOutputCharacterW failed\n");
ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
/* Output u9580 "count" times at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
}
/* Check cursor */
len = 1 + count;
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Fill by ideograph space */
c.X = c.Y = 0;
ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
ok(ret, "FillConsoleOutputCharacterW failed\n");
ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 6, "len was: %ld\n", len);
ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
/* Read attr at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
ok(ret, "ReadConsoleOutputAttribute failed\n");
ok(attr == ATTR, "attr was: %d\n", attr);
ok(len == 1, "len was %ld\n", len);
/* Read characters at (1,0) */
c.X = 1;
c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 6, "len was: %ld\n", len);
ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
/* Output u9580 "count" once at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
/* Read attr (1,0) */
c.X = 1;
c.Y = 0;
ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
ok(ret, "ReadConsoleOutputAttribute failed\n");
ok(attr == ATTR, "attr was: %d\n", attr);
ok(len == 1, "len was %ld\n", len);
/* Check cursor */
c.X = 2;
c.Y = 0;
okCURSOR(hConOut, c);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 6, "len was: %ld\n", len);
ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x9580 || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
}
/* Restore code page */
SetConsoleOutputCP(oldcp);
}
/* Japanese Code Page 932 */
static void test_cp932(HANDLE hConOut)
{
BOOL ret;
DWORD oldcp;
int n;
DWORD len;
COORD c;
CONSOLE_SCREEN_BUFFER_INFO csbi;
int count;
WCHAR str[32];
WORD attr;
if (!IsValidCodePage(932))
{
skip("Codepage 932 not available\n");
return;
}
/* Set code page */
oldcp = GetConsoleOutputCP();
SetLastError(0xdeadbeef);
ret = SetConsoleOutputCP(932);
if (!ret)
{
skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
return;
}
/* Get info */
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);
/* "\u0414" */
{
/* Output u0414 "count" times at (0,0) */
c.X = c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
}
/* Check cursor */
GetConsoleScreenBufferInfo(hConOut, &csbi);
len = count * 2; /* u0414 is fullwidth in Japanese */
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 3, "len was: %ld\n", len);
ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
/* Check cursor */
c.X = 1;
c.Y = 0;
ret = SetConsoleCursorPosition(hConOut, c);
ok(ret, "SetConsoleCursorPosition failed\n");
okCURSOR(hConOut, c);
/* Fill by space */
c.X = c.Y = 0;
FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
/* Output u0414 "count" times at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
}
/* Check cursor */
len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Read characters at (0,0) */
c.X = 0;
c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 4, "len was: %ld\n", len);
ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
}
/* "\u9580" */
{
/* Output u9580 "count" times at (0,0) */
c.X = c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
}
/* Check cursor */
len = count * 2; /* u9580 is fullwidth in Japanese */
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Check cursor */
c.X = 1;
c.Y = 0;
ret = SetConsoleCursorPosition(hConOut, c);
ok(ret, "SetConsoleCursorPosition failed\n");
okCURSOR(hConOut, c);
/* Fill by space */
c.X = c.Y = 0;
ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
ok(ret, "FillConsoleOutputCharacterW failed\n");
ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
/* Output u9580 "count" times at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
for (n = 0; n < count; ++n)
{
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
}
/* Check cursor */
len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
c.X = (SHORT)(len % csbi.dwSize.X);
c.Y = (SHORT)(len / csbi.dwSize.X);
okCURSOR(hConOut, c);
/* Fill by ideograph space */
c.X = c.Y = 0;
ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
ok(ret, "FillConsoleOutputCharacterW failed\n");
ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
/* Read characters at (0,0) */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 3, "len was: %ld\n", len);
ok(str[0] == ideograph_space, "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == ideograph_space, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == ideograph_space, "str[2] was: 0x%04X\n", str[2]);
/* Read attr */
ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
ok(ret, "ReadConsoleOutputAttribute failed\n");
ok(attr == ATTR, "attr was: %d\n", attr);
ok(len == 1, "len was %ld\n", len);
/* Output u9580 "count" once at (1,0) */
c.X = 1;
c.Y = 0;
SetConsoleCursorPosition(hConOut, c);
okCURSOR(hConOut, c);
ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
/* Read attr */
ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
ok(ret, "ReadConsoleOutputAttribute failed\n");
ok(attr == ATTR, "attr was: %d\n", attr);
ok(len == 1, "len was %ld\n", len);
/* Check cursor */
c.X = 3;
c.Y = 0;
okCURSOR(hConOut, c);
/* Read characters */
c.X = c.Y = 0;
ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
ok(ret, "ReadConsoleOutputCharacterW failed\n");
ok(len == 4, "len was: %ld\n", len);
ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
ok(str[1] == 0x9580, "str[1] was: 0x%04X\n", str[1]);
ok(str[2] == L' ', "str[2] was: 0x%04X\n", str[2]);
}
/* Restore code page */
SetConsoleOutputCP(oldcp);
}
START_TEST(Console)
{
HANDLE hConIn, hConOut;
FreeConsole();
ok(AllocConsole(), "Couldn't alloc console\n");
hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
if (IsValidLocale(lcidRussian, LCID_INSTALLED))
test_cp855(hConOut);
else
skip("Russian locale is not installed\n");
if (IsValidLocale(lcidJapanese, LCID_INSTALLED))
test_cp932(hConOut);
else
skip("Japanese locale is not installed\n");
CloseHandle(hConIn);
CloseHandle(hConOut);
FreeConsole();
ok(AllocConsole(), "Couldn't alloc console\n");
}