2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for i18n console test
5 * PROGRAMMERS: Katayama Hirofumi MZ
10 #define okCURSOR(hCon, c) do { \
11 CONSOLE_SCREEN_BUFFER_INFO __sbi; \
12 BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
13 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
14 ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
15 (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
19 (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
21 static const WCHAR u0414
[] = { 0x0414, 0 }; /* Д */
22 static const WCHAR u9580
[] = { 0x9580, 0 }; /* 門 */
23 static const WCHAR ideograph_space
= (WCHAR
)0x3000; /* fullwidth space */
24 LCID lcidJapanese
= MAKELCID(MAKELANGID(LANG_JAPANESE
, SUBLANG_DEFAULT
), SORT_DEFAULT
);
25 LCID lcidRussian
= MAKELCID(MAKELANGID(LANG_RUSSIAN
, SUBLANG_DEFAULT
), SORT_DEFAULT
);
27 static BOOL
IsCJKCodePage(void)
31 case 936: // Chinese PRC
34 case 1361: // Korean (Johab)
41 /* Russian Code Page 855 */
42 // NOTE that CP 866 can also be used
43 static void test_cp855(HANDLE hConOut
)
50 CONSOLE_SCREEN_BUFFER_INFO csbi
;
55 if (!IsValidCodePage(855))
57 skip("Codepage 855 not available\n");
62 oldcp
= GetConsoleOutputCP();
63 SetLastError(0xdeadbeef);
64 ret
= SetConsoleOutputCP(855);
67 skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
72 ret
= GetConsoleScreenBufferInfo(hConOut
, &csbi
);
73 ok(ret
, "GetConsoleScreenBufferInfo failed\n");
74 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi
.dwSize
.X
, csbi
.dwSize
.Y
);
75 count
= csbi
.dwSize
.X
* 3 / 2;
76 trace("count: %d\n", count
);
80 /* Output u0414 "count" times at (0,0) */
82 SetConsoleCursorPosition(hConOut
, c
);
84 for (n
= 0; n
< count
; ++n
)
86 ret
= WriteConsoleW(hConOut
, u0414
, lstrlenW(u0414
), &len
, NULL
);
87 ok(ret
&& len
== lstrlenW(u0414
), "WriteConsoleW failed\n");
91 len
= count
; /* u0414 is normal width in Russian */
92 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
93 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
96 /* Read characters at (0,0) */
98 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
99 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
100 ok(len
== 6, "len was: %ld\n", len
);
101 ok(str
[0] == 0x414, "str[0] was: 0x%04X\n", str
[0]);
102 ok(str
[1] == 0x414, "str[1] was: 0x%04X\n", str
[1]);
103 ok(str
[2] == 0x414, "str[2] was: 0x%04X\n", str
[2]);
108 ret
= SetConsoleCursorPosition(hConOut
, c
);
109 ok(ret
, "SetConsoleCursorPosition failed\n");
110 okCURSOR(hConOut
, c
);
114 FillConsoleOutputCharacterW(hConOut
, L
' ', csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
116 /* Output u0414 "count" times at (1,0) */
119 SetConsoleCursorPosition(hConOut
, c
);
120 okCURSOR(hConOut
, c
);
121 for (n
= 0; n
< count
; ++n
)
123 ret
= WriteConsoleW(hConOut
, u0414
, lstrlenW(u0414
), &len
, NULL
);
124 ok(ret
&& len
== lstrlenW(u0414
), "WriteConsoleW failed\n");
129 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
130 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
131 okCURSOR(hConOut
, c
);
133 /* Read characters at (0,0) */
135 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
136 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
137 ok(len
== 6, "len was: %ld\n", len
);
138 ok(str
[0] == L
' ', "str[0] was: 0x%04X\n", str
[0]);
139 ok(str
[1] == 0x414, "str[1] was: 0x%04X\n", str
[1]);
140 ok(str
[2] == 0x414, "str[2] was: 0x%04X\n", str
[2]);
145 /* Output u9580 "count" times at (0,0) */
147 SetConsoleCursorPosition(hConOut
, c
);
148 okCURSOR(hConOut
, c
);
149 for (n
= 0; n
< count
; ++n
)
151 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
152 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
156 len
= count
; /* u9580 is normal width in Russian */
157 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
158 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
159 okCURSOR(hConOut
, c
);
164 ret
= SetConsoleCursorPosition(hConOut
, c
);
165 ok(ret
, "SetConsoleCursorPosition failed\n");
166 okCURSOR(hConOut
, c
);
170 ret
= FillConsoleOutputCharacterW(hConOut
, L
' ', csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
171 ok(ret
, "FillConsoleOutputCharacterW failed\n");
172 ok(len
== csbi
.dwSize
.X
* csbi
.dwSize
.Y
, "len was: %ld\n", len
);
174 /* Output u9580 "count" times at (1,0) */
177 SetConsoleCursorPosition(hConOut
, c
);
178 okCURSOR(hConOut
, c
);
179 for (n
= 0; n
< count
; ++n
)
181 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
182 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
187 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
188 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
189 okCURSOR(hConOut
, c
);
191 /* Fill by ideograph space */
193 ret
= FillConsoleOutputCharacterW(hConOut
, ideograph_space
, csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
194 ok(ret
, "FillConsoleOutputCharacterW failed\n");
195 ok(len
== csbi
.dwSize
.X
* csbi
.dwSize
.Y
, "len was: %ld\n", len
);
197 /* Read characters at (0,0) */
199 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
200 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
201 ok(len
== 6, "len was: %ld\n", len
);
202 ok(str
[0] == ideograph_space
|| str
[0] == L
'?', "str[0] was: 0x%04X\n", str
[0]);
203 ok(str
[1] == ideograph_space
|| str
[1] == L
'?', "str[1] was: 0x%04X\n", str
[1]);
204 ok(str
[2] == ideograph_space
|| str
[2] == L
'?', "str[2] was: 0x%04X\n", str
[2]);
206 /* Read attr at (0,0) */
208 ret
= ReadConsoleOutputAttribute(hConOut
, &attr
, 1, c
, &len
);
209 ok(ret
, "ReadConsoleOutputAttribute failed\n");
210 ok(attr
== ATTR
, "attr was: %d\n", attr
);
211 ok(len
== 1, "len was %ld\n", len
);
213 /* Read characters at (1,0) */
216 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
217 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
218 ok(len
== 6, "len was: %ld\n", len
);
219 ok(str
[0] == ideograph_space
|| str
[0] == L
'?', "str[0] was: 0x%04X\n", str
[0]);
220 ok(str
[1] == ideograph_space
|| str
[1] == L
'?', "str[1] was: 0x%04X\n", str
[1]);
221 ok(str
[2] == ideograph_space
|| str
[2] == L
'?', "str[2] was: 0x%04X\n", str
[2]);
223 /* Output u9580 "count" once at (1,0) */
226 SetConsoleCursorPosition(hConOut
, c
);
227 okCURSOR(hConOut
, c
);
228 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
229 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
231 /* Read attr (1,0) */
234 ret
= ReadConsoleOutputAttribute(hConOut
, &attr
, 1, c
, &len
);
235 ok(ret
, "ReadConsoleOutputAttribute failed\n");
236 ok(attr
== ATTR
, "attr was: %d\n", attr
);
237 ok(len
== 1, "len was %ld\n", len
);
242 okCURSOR(hConOut
, c
);
244 /* Read characters at (0,0) */
246 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
247 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
248 ok(len
== 6, "len was: %ld\n", len
);
249 ok(str
[0] == ideograph_space
|| str
[0] == L
'?', "str[0] was: 0x%04X\n", str
[0]);
250 ok(str
[1] == 0x9580 || str
[1] == L
'?', "str[1] was: 0x%04X\n", str
[1]);
251 ok(str
[2] == ideograph_space
|| str
[2] == L
'?', "str[2] was: 0x%04X\n", str
[2]);
254 /* Restore code page */
255 SetConsoleOutputCP(oldcp
);
258 /* Japanese Code Page 932 */
259 static void test_cp932(HANDLE hConOut
)
266 CONSOLE_SCREEN_BUFFER_INFO csbi
;
271 if (!IsValidCodePage(932))
273 skip("Codepage 932 not available\n");
278 oldcp
= GetConsoleOutputCP();
279 SetLastError(0xdeadbeef);
280 ret
= SetConsoleOutputCP(932);
283 skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
288 ret
= GetConsoleScreenBufferInfo(hConOut
, &csbi
);
289 ok(ret
, "GetConsoleScreenBufferInfo failed\n");
290 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi
.dwSize
.X
, csbi
.dwSize
.Y
);
291 count
= csbi
.dwSize
.X
* 3 / 2;
292 trace("count: %d\n", count
);
296 /* Output u0414 "count" times at (0,0) */
298 SetConsoleCursorPosition(hConOut
, c
);
299 okCURSOR(hConOut
, c
);
300 for (n
= 0; n
< count
; ++n
)
302 ret
= WriteConsoleW(hConOut
, u0414
, lstrlenW(u0414
), &len
, NULL
);
303 ok(ret
&& len
== lstrlenW(u0414
), "WriteConsoleW failed\n");
307 GetConsoleScreenBufferInfo(hConOut
, &csbi
);
308 len
= count
* 2; /* u0414 is fullwidth in Japanese */
309 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
310 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
311 okCURSOR(hConOut
, c
);
313 /* Read characters at (0,0) */
315 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
316 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
317 ok(len
== 3, "len was: %ld\n", len
);
318 ok(str
[0] == 0x414, "str[0] was: 0x%04X\n", str
[0]);
319 ok(str
[1] == 0x414, "str[1] was: 0x%04X\n", str
[1]);
320 ok(str
[2] == 0x414, "str[2] was: 0x%04X\n", str
[2]);
325 ret
= SetConsoleCursorPosition(hConOut
, c
);
326 ok(ret
, "SetConsoleCursorPosition failed\n");
327 okCURSOR(hConOut
, c
);
331 FillConsoleOutputCharacterW(hConOut
, L
' ', csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
333 /* Output u0414 "count" times at (1,0) */
336 SetConsoleCursorPosition(hConOut
, c
);
337 okCURSOR(hConOut
, c
);
338 for (n
= 0; n
< count
; ++n
)
340 ret
= WriteConsoleW(hConOut
, u0414
, lstrlenW(u0414
), &len
, NULL
);
341 ok(ret
&& len
== lstrlenW(u0414
), "WriteConsoleW failed\n");
345 len
= csbi
.dwSize
.X
+ (count
- (csbi
.dwSize
.X
- 1) / 2) * 2;
346 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
347 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
348 okCURSOR(hConOut
, c
);
350 /* Read characters at (0,0) */
353 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
354 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
355 ok(len
== 4, "len was: %ld\n", len
);
356 ok(str
[0] == L
' ', "str[0] was: 0x%04X\n", str
[0]);
357 ok(str
[1] == 0x414, "str[1] was: 0x%04X\n", str
[1]);
358 ok(str
[2] == 0x414, "str[2] was: 0x%04X\n", str
[2]);
363 /* Output u9580 "count" times at (0,0) */
365 SetConsoleCursorPosition(hConOut
, c
);
366 okCURSOR(hConOut
, c
);
367 for (n
= 0; n
< count
; ++n
)
369 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
370 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
374 len
= count
* 2; /* u9580 is fullwidth in Japanese */
375 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
376 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
377 okCURSOR(hConOut
, c
);
382 ret
= SetConsoleCursorPosition(hConOut
, c
);
383 ok(ret
, "SetConsoleCursorPosition failed\n");
384 okCURSOR(hConOut
, c
);
388 ret
= FillConsoleOutputCharacterW(hConOut
, L
' ', csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
389 ok(ret
, "FillConsoleOutputCharacterW failed\n");
390 ok(len
== csbi
.dwSize
.X
* csbi
.dwSize
.Y
, "len was: %ld\n", len
);
392 /* Output u9580 "count" times at (1,0) */
395 SetConsoleCursorPosition(hConOut
, c
);
396 okCURSOR(hConOut
, c
);
397 for (n
= 0; n
< count
; ++n
)
399 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
400 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
404 len
= csbi
.dwSize
.X
+ (count
- (csbi
.dwSize
.X
- 1) / 2) * 2;
405 c
.X
= (SHORT
)(len
% csbi
.dwSize
.X
);
406 c
.Y
= (SHORT
)(len
/ csbi
.dwSize
.X
);
407 okCURSOR(hConOut
, c
);
409 /* Fill by ideograph space */
411 ret
= FillConsoleOutputCharacterW(hConOut
, ideograph_space
, csbi
.dwSize
.X
* csbi
.dwSize
.Y
, c
, &len
);
412 ok(ret
, "FillConsoleOutputCharacterW failed\n");
413 ok(len
== csbi
.dwSize
.X
* csbi
.dwSize
.Y
, "len was: %ld\n", len
);
415 /* Read characters at (0,0) */
417 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
418 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
419 ok(len
== 3, "len was: %ld\n", len
);
420 ok(str
[0] == ideograph_space
, "str[0] was: 0x%04X\n", str
[0]);
421 ok(str
[1] == ideograph_space
, "str[1] was: 0x%04X\n", str
[1]);
422 ok(str
[2] == ideograph_space
, "str[2] was: 0x%04X\n", str
[2]);
425 ret
= ReadConsoleOutputAttribute(hConOut
, &attr
, 1, c
, &len
);
426 ok(ret
, "ReadConsoleOutputAttribute failed\n");
427 ok(attr
== ATTR
, "attr was: %d\n", attr
);
428 ok(len
== 1, "len was %ld\n", len
);
430 /* Output u9580 "count" once at (1,0) */
433 SetConsoleCursorPosition(hConOut
, c
);
434 okCURSOR(hConOut
, c
);
435 ret
= WriteConsoleW(hConOut
, u9580
, lstrlenW(u9580
), &len
, NULL
);
436 ok(ret
&& len
== lstrlenW(u9580
), "WriteConsoleW failed\n");
439 ret
= ReadConsoleOutputAttribute(hConOut
, &attr
, 1, c
, &len
);
440 ok(ret
, "ReadConsoleOutputAttribute failed\n");
441 ok(attr
== ATTR
, "attr was: %d\n", attr
);
442 ok(len
== 1, "len was %ld\n", len
);
447 okCURSOR(hConOut
, c
);
449 /* Read characters */
451 ret
= ReadConsoleOutputCharacterW(hConOut
, str
, 3 * sizeof(WCHAR
), c
, &len
);
452 ok(ret
, "ReadConsoleOutputCharacterW failed\n");
453 ok(len
== 4, "len was: %ld\n", len
);
454 ok(str
[0] == L
' ', "str[0] was: 0x%04X\n", str
[0]);
455 ok(str
[1] == 0x9580, "str[1] was: 0x%04X\n", str
[1]);
456 ok(str
[2] == L
' ', "str[2] was: 0x%04X\n", str
[2]);
459 /* Restore code page */
460 SetConsoleOutputCP(oldcp
);
463 START_TEST(ConsoleCP
)
465 HANDLE hConIn
, hConOut
;
467 ok(AllocConsole(), "Couldn't alloc console\n");
469 hConIn
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
470 hConOut
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
471 ok(hConIn
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
472 ok(hConOut
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
474 if (IsValidLocale(lcidRussian
, LCID_INSTALLED
))
476 if (!IsCJKCodePage())
479 skip("Russian testcase is skipped because of CJK\n");
483 skip("Russian locale is not installed\n");
486 if (IsValidLocale(lcidJapanese
, LCID_INSTALLED
))
491 skip("Japanese testcase is skipped because of not CJK\n");
495 skip("Japanese locale is not installed\n");
499 CloseHandle(hConOut
);
501 ok(AllocConsole(), "Couldn't alloc console\n");