5d12bd88c5cd307b6742e97731354c7f20b411ca
[reactos.git] / modules / rostests / apitests / kernel32 / ConsoleCP.c
1 /*
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
6 */
7
8 #include "precomp.h"
9
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); \
16 } while (0)
17
18 #define ATTR \
19 (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
20
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);
26
27 /* Russian Code Page 855 */
28 // NOTE that CP 866 can also be used
29 static void test_cp855(HANDLE hConOut)
30 {
31 BOOL ret;
32 DWORD oldcp;
33 int n;
34 DWORD len;
35 COORD c;
36 CONSOLE_SCREEN_BUFFER_INFO csbi;
37 int count;
38 WCHAR str[32];
39 WORD attr;
40
41 if (!IsValidCodePage(855))
42 {
43 skip("Codepage 855 not available\n");
44 return;
45 }
46
47 /* Set code page */
48 oldcp = GetConsoleOutputCP();
49 SetLastError(0xdeadbeef);
50 ret = SetConsoleOutputCP(855);
51 if (!ret)
52 {
53 skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
54 return;
55 }
56
57 /* Get info */
58 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
59 ok(ret, "GetConsoleScreenBufferInfo failed\n");
60 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
61 count = csbi.dwSize.X * 3 / 2;
62 trace("count: %d\n", count);
63
64 /* "\u0414" */
65 {
66 /* Output u0414 "count" times at (0,0) */
67 c.X = c.Y = 0;
68 SetConsoleCursorPosition(hConOut, c);
69 okCURSOR(hConOut, c);
70 for (n = 0; n < count; ++n)
71 {
72 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
73 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
74 }
75
76 /* Check cursor */
77 len = count; /* u0414 is normal width in Russian */
78 c.X = (SHORT)(len % csbi.dwSize.X);
79 c.Y = (SHORT)(len / csbi.dwSize.X);
80 okCURSOR(hConOut, c);
81
82 /* Read characters at (0,0) */
83 c.X = c.Y = 0;
84 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
85 ok(ret, "ReadConsoleOutputCharacterW failed\n");
86 ok(len == 6, "len was: %ld\n", len);
87 ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]);
88 ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
89 ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
90
91 /* Check cursor */
92 c.X = 1;
93 c.Y = 0;
94 ret = SetConsoleCursorPosition(hConOut, c);
95 ok(ret, "SetConsoleCursorPosition failed\n");
96 okCURSOR(hConOut, c);
97
98 /* Fill by space */
99 c.X = c.Y = 0;
100 FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
101
102 /* Output u0414 "count" times at (1,0) */
103 c.X = 1;
104 c.Y = 0;
105 SetConsoleCursorPosition(hConOut, c);
106 okCURSOR(hConOut, c);
107 for (n = 0; n < count; ++n)
108 {
109 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
110 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
111 }
112
113 /* Check cursor */
114 len = 1 + count;
115 c.X = (SHORT)(len % csbi.dwSize.X);
116 c.Y = (SHORT)(len / csbi.dwSize.X);
117 okCURSOR(hConOut, c);
118
119 /* Read characters at (0,0) */
120 c.X = c.Y = 0;
121 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
122 ok(ret, "ReadConsoleOutputCharacterW failed\n");
123 ok(len == 6, "len was: %ld\n", len);
124 ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
125 ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
126 ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
127 }
128
129 /* "\u9580" */
130 {
131 /* Output u9580 "count" times at (0,0) */
132 c.X = c.Y = 0;
133 SetConsoleCursorPosition(hConOut, c);
134 okCURSOR(hConOut, c);
135 for (n = 0; n < count; ++n)
136 {
137 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
138 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
139 }
140
141 /* Check cursor */
142 len = count; /* u9580 is normal width in Russian */
143 c.X = (SHORT)(len % csbi.dwSize.X);
144 c.Y = (SHORT)(len / csbi.dwSize.X);
145 okCURSOR(hConOut, c);
146
147 /* Check cursor */
148 c.X = 1;
149 c.Y = 0;
150 ret = SetConsoleCursorPosition(hConOut, c);
151 ok(ret, "SetConsoleCursorPosition failed\n");
152 okCURSOR(hConOut, c);
153
154 /* Fill by space */
155 c.X = c.Y = 0;
156 ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
157 ok(ret, "FillConsoleOutputCharacterW failed\n");
158 ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
159
160 /* Output u9580 "count" times at (1,0) */
161 c.X = 1;
162 c.Y = 0;
163 SetConsoleCursorPosition(hConOut, c);
164 okCURSOR(hConOut, c);
165 for (n = 0; n < count; ++n)
166 {
167 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
168 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
169 }
170
171 /* Check cursor */
172 len = 1 + count;
173 c.X = (SHORT)(len % csbi.dwSize.X);
174 c.Y = (SHORT)(len / csbi.dwSize.X);
175 okCURSOR(hConOut, c);
176
177 /* Fill by ideograph space */
178 c.X = c.Y = 0;
179 ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
180 ok(ret, "FillConsoleOutputCharacterW failed\n");
181 ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
182
183 /* Read characters at (0,0) */
184 c.X = c.Y = 0;
185 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
186 ok(ret, "ReadConsoleOutputCharacterW failed\n");
187 ok(len == 6, "len was: %ld\n", len);
188 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
189 ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
190 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
191
192 /* Read attr at (0,0) */
193 c.X = c.Y = 0;
194 ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
195 ok(ret, "ReadConsoleOutputAttribute failed\n");
196 ok(attr == ATTR, "attr was: %d\n", attr);
197 ok(len == 1, "len was %ld\n", len);
198
199 /* Read characters at (1,0) */
200 c.X = 1;
201 c.Y = 0;
202 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
203 ok(ret, "ReadConsoleOutputCharacterW failed\n");
204 ok(len == 6, "len was: %ld\n", len);
205 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
206 ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
207 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
208
209 /* Output u9580 "count" once at (1,0) */
210 c.X = 1;
211 c.Y = 0;
212 SetConsoleCursorPosition(hConOut, c);
213 okCURSOR(hConOut, c);
214 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
215 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
216
217 /* Read attr (1,0) */
218 c.X = 1;
219 c.Y = 0;
220 ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
221 ok(ret, "ReadConsoleOutputAttribute failed\n");
222 ok(attr == ATTR, "attr was: %d\n", attr);
223 ok(len == 1, "len was %ld\n", len);
224
225 /* Check cursor */
226 c.X = 2;
227 c.Y = 0;
228 okCURSOR(hConOut, c);
229
230 /* Read characters at (0,0) */
231 c.X = c.Y = 0;
232 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
233 ok(ret, "ReadConsoleOutputCharacterW failed\n");
234 ok(len == 6, "len was: %ld\n", len);
235 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
236 ok(str[1] == 0x9580 || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
237 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
238 }
239
240 /* Restore code page */
241 SetConsoleOutputCP(oldcp);
242 }
243
244 /* Japanese Code Page 932 */
245 static void test_cp932(HANDLE hConOut)
246 {
247 BOOL ret;
248 DWORD oldcp;
249 int n;
250 DWORD len;
251 COORD c;
252 CONSOLE_SCREEN_BUFFER_INFO csbi;
253 int count;
254 WCHAR str[32];
255 WORD attr;
256
257 if (!IsValidCodePage(932))
258 {
259 skip("Codepage 932 not available\n");
260 return;
261 }
262
263 /* Set code page */
264 oldcp = GetConsoleOutputCP();
265 SetLastError(0xdeadbeef);
266 ret = SetConsoleOutputCP(932);
267 if (!ret)
268 {
269 skip("SetConsoleOutputCP failed with last error %lu\n", GetLastError());
270 return;
271 }
272
273 /* Get info */
274 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
275 ok(ret, "GetConsoleScreenBufferInfo failed\n");
276 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
277 count = csbi.dwSize.X * 3 / 2;
278 trace("count: %d\n", count);
279
280 /* "\u0414" */
281 {
282 /* Output u0414 "count" times at (0,0) */
283 c.X = c.Y = 0;
284 SetConsoleCursorPosition(hConOut, c);
285 okCURSOR(hConOut, c);
286 for (n = 0; n < count; ++n)
287 {
288 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
289 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
290 }
291
292 /* Check cursor */
293 GetConsoleScreenBufferInfo(hConOut, &csbi);
294 len = count * 2; /* u0414 is fullwidth in Japanese */
295 c.X = (SHORT)(len % csbi.dwSize.X);
296 c.Y = (SHORT)(len / csbi.dwSize.X);
297 okCURSOR(hConOut, c);
298
299 /* Read characters at (0,0) */
300 c.X = c.Y = 0;
301 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
302 ok(ret, "ReadConsoleOutputCharacterW failed\n");
303 ok(len == 3, "len was: %ld\n", len);
304 ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]);
305 ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
306 ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
307
308 /* Check cursor */
309 c.X = 1;
310 c.Y = 0;
311 ret = SetConsoleCursorPosition(hConOut, c);
312 ok(ret, "SetConsoleCursorPosition failed\n");
313 okCURSOR(hConOut, c);
314
315 /* Fill by space */
316 c.X = c.Y = 0;
317 FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
318
319 /* Output u0414 "count" times at (1,0) */
320 c.X = 1;
321 c.Y = 0;
322 SetConsoleCursorPosition(hConOut, c);
323 okCURSOR(hConOut, c);
324 for (n = 0; n < count; ++n)
325 {
326 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
327 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
328 }
329
330 /* Check cursor */
331 len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
332 c.X = (SHORT)(len % csbi.dwSize.X);
333 c.Y = (SHORT)(len / csbi.dwSize.X);
334 okCURSOR(hConOut, c);
335
336 /* Read characters at (0,0) */
337 c.X = 0;
338 c.Y = 0;
339 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
340 ok(ret, "ReadConsoleOutputCharacterW failed\n");
341 ok(len == 4, "len was: %ld\n", len);
342 ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
343 ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]);
344 ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]);
345 }
346
347 /* "\u9580" */
348 {
349 /* Output u9580 "count" times at (0,0) */
350 c.X = c.Y = 0;
351 SetConsoleCursorPosition(hConOut, c);
352 okCURSOR(hConOut, c);
353 for (n = 0; n < count; ++n)
354 {
355 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
356 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
357 }
358
359 /* Check cursor */
360 len = count * 2; /* u9580 is fullwidth in Japanese */
361 c.X = (SHORT)(len % csbi.dwSize.X);
362 c.Y = (SHORT)(len / csbi.dwSize.X);
363 okCURSOR(hConOut, c);
364
365 /* Check cursor */
366 c.X = 1;
367 c.Y = 0;
368 ret = SetConsoleCursorPosition(hConOut, c);
369 ok(ret, "SetConsoleCursorPosition failed\n");
370 okCURSOR(hConOut, c);
371
372 /* Fill by space */
373 c.X = c.Y = 0;
374 ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
375 ok(ret, "FillConsoleOutputCharacterW failed\n");
376 ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
377
378 /* Output u9580 "count" times at (1,0) */
379 c.X = 1;
380 c.Y = 0;
381 SetConsoleCursorPosition(hConOut, c);
382 okCURSOR(hConOut, c);
383 for (n = 0; n < count; ++n)
384 {
385 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
386 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
387 }
388
389 /* Check cursor */
390 len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
391 c.X = (SHORT)(len % csbi.dwSize.X);
392 c.Y = (SHORT)(len / csbi.dwSize.X);
393 okCURSOR(hConOut, c);
394
395 /* Fill by ideograph space */
396 c.X = c.Y = 0;
397 ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
398 ok(ret, "FillConsoleOutputCharacterW failed\n");
399 ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len);
400
401 /* Read characters at (0,0) */
402 c.X = c.Y = 0;
403 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
404 ok(ret, "ReadConsoleOutputCharacterW failed\n");
405 ok(len == 3, "len was: %ld\n", len);
406 ok(str[0] == ideograph_space, "str[0] was: 0x%04X\n", str[0]);
407 ok(str[1] == ideograph_space, "str[1] was: 0x%04X\n", str[1]);
408 ok(str[2] == ideograph_space, "str[2] was: 0x%04X\n", str[2]);
409
410 /* Read attr */
411 ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len);
412 ok(ret, "ReadConsoleOutputAttribute failed\n");
413 ok(attr == ATTR, "attr was: %d\n", attr);
414 ok(len == 1, "len was %ld\n", len);
415
416 /* Output u9580 "count" once at (1,0) */
417 c.X = 1;
418 c.Y = 0;
419 SetConsoleCursorPosition(hConOut, c);
420 okCURSOR(hConOut, c);
421 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
422 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
423
424 /* Read attr */
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);
429
430 /* Check cursor */
431 c.X = 3;
432 c.Y = 0;
433 okCURSOR(hConOut, c);
434
435 /* Read characters */
436 c.X = c.Y = 0;
437 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
438 ok(ret, "ReadConsoleOutputCharacterW failed\n");
439 ok(len == 4, "len was: %ld\n", len);
440 ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]);
441 ok(str[1] == 0x9580, "str[1] was: 0x%04X\n", str[1]);
442 ok(str[2] == L' ', "str[2] was: 0x%04X\n", str[2]);
443 }
444
445 /* Restore code page */
446 SetConsoleOutputCP(oldcp);
447 }
448
449 START_TEST(ConsoleCP)
450 {
451 HANDLE hConIn, hConOut;
452 FreeConsole();
453 ok(AllocConsole(), "Couldn't alloc console\n");
454
455 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
456 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
457 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
458 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
459
460 if (IsValidLocale(lcidRussian, LCID_INSTALLED))
461 test_cp855(hConOut);
462 else
463 skip("Russian locale is not installed\n");
464
465 if (IsValidLocale(lcidJapanese, LCID_INSTALLED))
466 test_cp932(hConOut);
467 else
468 skip("Japanese locale is not installed\n");
469
470 CloseHandle(hConIn);
471 CloseHandle(hConOut);
472 FreeConsole();
473 ok(AllocConsole(), "Couldn't alloc console\n");
474 }