installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / misc / UnicodeDoubleWidthTest.cc
1 // Demonstrates how U+30FC is sometimes handled as a single-width character
2 // when it should be handled as a double-width character.
3 //
4 // It only runs on computers where 932 is a valid code page.  Set the system
5 // local to "Japanese (Japan)" to ensure this.
6 //
7 // The problem seems to happen when U+30FC is printed in a console using the
8 // Lucida Console font, and only when that font is at certain sizes.
9 //
10
11 #include <windows.h>
12 #include <assert.h>
13 #include <locale.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "TestUtil.cc"
19
20 #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
21
22 static void setFont(const wchar_t *faceName, int pxSize) {
23     CONSOLE_FONT_INFOEX infoex = {0};
24     infoex.cbSize = sizeof(infoex);
25     infoex.dwFontSize.Y = pxSize;
26     wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName));
27     BOOL ret = SetCurrentConsoleFontEx(
28         GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex);
29     assert(ret);
30 }
31
32 static bool performTest(const wchar_t testChar) {
33     const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
34
35     SetConsoleTextAttribute(conout, 7);
36
37     system("cls");
38     DWORD actual = 0;
39     BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL);
40     assert(ret && actual == 1);
41
42     CHAR_INFO verify[2];
43     COORD bufSize = {2, 1};
44     COORD bufCoord = {0, 0};
45     const SMALL_RECT readRegion = {0, 0, 1, 0};
46     SMALL_RECT actualRegion = readRegion;
47     ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion);
48     assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion)));
49     assert(verify[0].Char.UnicodeChar == testChar);
50
51     if (verify[1].Char.UnicodeChar == testChar) {
52         // Typical double-width behavior with a TrueType font.  Pass.
53         assert(verify[0].Attributes == 0x107);
54         assert(verify[1].Attributes == 0x207);
55         return true;
56     } else if (verify[1].Char.UnicodeChar == 0) {
57         // Typical double-width behavior with a Raster Font.  Pass.
58         assert(verify[0].Attributes == 7);
59         assert(verify[1].Attributes == 0);
60         return true;
61     } else if (verify[1].Char.UnicodeChar == L' ') {
62         // Single-width behavior.  Fail.
63         assert(verify[0].Attributes == 7);
64         assert(verify[1].Attributes == 7);
65         return false;
66     } else {
67         // Unexpected output.
68         assert(false);
69     }
70 }
71
72 int main(int argc, char *argv[]) {
73     setlocale(LC_ALL, "");
74     if (argc == 1) {
75         startChildProcess(L"CHILD");
76         return 0;
77     }
78
79     assert(SetConsoleCP(932));
80     assert(SetConsoleOutputCP(932));
81
82     const wchar_t testChar = 0x30FC;
83     const wchar_t *const faceNames[] = {
84         L"Lucida Console",
85         L"Consolas",
86         L"MS ゴシック",
87     };
88
89     trace("Test started");
90
91     for (auto faceName : faceNames) {
92         for (int px = 1; px <= 50; ++px) {
93             setFont(faceName, px);
94             if (!performTest(testChar)) {
95                 trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px);
96             }
97         }
98     }
99
100     trace("Test complete");
101     return 0;
102 }