installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / misc / UnicodeWideTest1.cc
1 #include <windows.h>
2
3 #include <assert.h>
4 #include <vector>
5
6 #include "TestUtil.cc"
7
8 #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
9
10
11 CHAR_INFO ci(wchar_t ch, WORD attributes) {
12     CHAR_INFO ret;
13     ret.Char.UnicodeChar = ch;
14     ret.Attributes = attributes;
15     return ret;
16 }
17
18 CHAR_INFO ci(wchar_t ch) {
19     return ci(ch, 7);
20 }
21
22 CHAR_INFO ci() {
23     return ci(L' ');
24 }
25
26 bool operator==(SMALL_RECT x, SMALL_RECT y) {
27     return !memcmp(&x, &y, sizeof(x));
28 }
29
30 SMALL_RECT sr(COORD pt, COORD size) {
31     return {
32         pt.X, pt.Y,
33         static_cast<SHORT>(pt.X + size.X - 1),
34         static_cast<SHORT>(pt.Y + size.Y - 1)
35     };
36 }
37
38 static void set(
39         const COORD pt,
40         const COORD size,
41         const std::vector<CHAR_INFO> &data) {
42     assert(data.size() == size.X * size.Y);
43     SMALL_RECT writeRegion = sr(pt, size);
44     BOOL ret = WriteConsoleOutputW(
45         GetStdHandle(STD_OUTPUT_HANDLE),
46         data.data(), size, {0, 0}, &writeRegion);
47     assert(ret && writeRegion == sr(pt, size));
48 }
49
50 static void set(
51         const COORD pt,
52         const std::vector<CHAR_INFO> &data) {
53     set(pt, {static_cast<SHORT>(data.size()), 1}, data);
54 }
55
56 static void writeAttrsAt(
57         const COORD pt,
58         const std::vector<WORD> &data) {
59     DWORD actual = 0;
60     BOOL ret = WriteConsoleOutputAttribute(
61         GetStdHandle(STD_OUTPUT_HANDLE),
62         data.data(), data.size(), pt, &actual);
63     assert(ret && actual == data.size());
64 }
65
66 static void writeCharsAt(
67         const COORD pt,
68         const std::vector<wchar_t> &data) {
69     DWORD actual = 0;
70     BOOL ret = WriteConsoleOutputCharacterW(
71         GetStdHandle(STD_OUTPUT_HANDLE),
72         data.data(), data.size(), pt, &actual);
73     assert(ret && actual == data.size());
74 }
75
76 static void writeChars(
77         const std::vector<wchar_t> &data) {
78     DWORD actual = 0;
79     BOOL ret = WriteConsoleW(
80         GetStdHandle(STD_OUTPUT_HANDLE),
81         data.data(), data.size(), &actual, NULL);
82     assert(ret && actual == data.size());
83 }
84
85 std::vector<CHAR_INFO> get(
86         const COORD pt,
87         const COORD size) {
88     std::vector<CHAR_INFO> data(size.X * size.Y);
89     SMALL_RECT readRegion = sr(pt, size);
90     BOOL ret = ReadConsoleOutputW(
91         GetStdHandle(STD_OUTPUT_HANDLE),
92         data.data(), size, {0, 0}, &readRegion);
93     assert(ret && readRegion == sr(pt, size));
94     return data;
95 }
96
97 std::vector<wchar_t> readCharsAt(
98         const COORD pt,
99         int size) {
100     std::vector<wchar_t> data(size);
101     DWORD actual = 0;
102     BOOL ret = ReadConsoleOutputCharacterW(
103         GetStdHandle(STD_OUTPUT_HANDLE),
104         data.data(), data.size(), pt, &actual);
105     assert(ret);
106     data.resize(actual); // With double-width chars, we can read fewer than `size`.
107     return data;
108 }
109
110 static void dump(const COORD pt, const COORD size) {
111     for (CHAR_INFO ci : get(pt, size)) {
112         printf("%04X %04X\n", ci.Char.UnicodeChar, ci.Attributes);
113     }
114 }
115
116 static void dumpCharsAt(const COORD pt, int size) {
117     for (wchar_t ch : readCharsAt(pt, size)) {
118         printf("%04X\n", ch);
119     }
120 }
121
122 static COORD getCursorPos() {
123     CONSOLE_SCREEN_BUFFER_INFO info = { sizeof(info) };
124     assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info));
125     return info.dwCursorPosition;
126 }
127
128 static void test1() {
129     // We write "䀀䀀", then write "䀁" in the middle of the two.  The second
130     // write turns the first and last cells into spaces.  The LEADING/TRAILING
131     // flags retain consistency.
132     printf("test1 - overlap full-width char with full-width char\n");
133     writeCharsAt({1,0}, {0x4000, 0x4000});
134     dump({0,0}, {6,1});
135     printf("\n");
136     writeCharsAt({2,0}, {0x4001});
137     dump({0,0}, {6,1});
138     printf("\n");
139 }
140
141 static void test2() {
142     // Like `test1`, but use a lower-level API to do the write.  Consistency is
143     // preserved here too -- the first and last cells are replaced with spaces.
144     printf("test2 - overlap full-width char with full-width char (lowlevel)\n");
145     writeCharsAt({1,0}, {0x4000, 0x4000});
146     dump({0,0}, {6,1});
147     printf("\n");
148     set({2,0}, {ci(0x4001,0x107), ci(0x4001,0x207)});
149     dump({0,0}, {6,1});
150     printf("\n");
151 }
152
153 static void test3() {
154     // However, the lower-level API can break the LEADING/TRAILING invariant
155     // explicitly:
156     printf("test3 - explicitly violate LEADING/TRAILING using lowlevel API\n");
157     set({1,0}, {
158         ci(0x4000, 0x207),
159         ci(0x4001, 0x107),
160         ci(0x3044, 7),
161         ci(L'X', 0x107),
162         ci(L'X', 0x207),
163     });
164     dump({0,0}, {7,1});
165 }
166
167 static void test4() {
168     // It is possible for the two cells of a double-width character to have two
169     // colors.
170     printf("test4 - use lowlevel to assign two colors to one full-width char\n");
171     set({0,0}, {
172         ci(0x4000, 0x142),
173         ci(0x4000, 0x224),
174     });
175     dump({0,0}, {2,1});
176 }
177
178 static void test5() {
179     // WriteConsoleOutputAttribute doesn't seem to affect the LEADING/TRAILING
180     // flags.
181     printf("test5 - WriteConsoleOutputAttribute cannot affect LEADING/TRAILING\n");
182
183     // Trying to clear the flags doesn't work...
184     writeCharsAt({0,0}, {0x4000});
185     dump({0,0}, {2,1});
186     writeAttrsAt({0,0}, {0x42, 0x24});
187     printf("\n");
188     dump({0,0}, {2,1});
189
190     // ... and trying to add them also doesn't work.
191     writeCharsAt({0,1}, {'A', ' '});
192     writeAttrsAt({0,1}, {0x107, 0x207});
193     printf("\n");
194     dump({0,1}, {2,1});
195 }
196
197 static void test6() {
198     // The cursor position may be on either cell of a double-width character.
199     // Visually, the cursor appears under both cells, regardless of which
200     // specific one has the cursor.
201     printf("test6 - cursor can be either left or right cell of full-width char\n");
202
203     writeCharsAt({2,1}, {0x4000});
204
205     setCursorPos(2, 1);
206     auto pos1 = getCursorPos();
207     Sleep(1000);
208
209     setCursorPos(3, 1);
210     auto pos2 = getCursorPos();
211     Sleep(1000);
212
213     setCursorPos(0, 15);
214     printf("%d,%d\n", pos1.X, pos1.Y);
215     printf("%d,%d\n", pos2.X, pos2.Y);
216 }
217
218 static void runTest(void (&test)()) {
219     system("cls");
220     setCursorPos(0, 14);
221     test();
222     system("pause");
223 }
224
225 int main(int argc, char *argv[]) {
226     if (argc == 1) {
227         startChildProcess(L"CHILD");
228         return 0;
229     }
230
231     setWindowPos(0, 0, 1, 1);
232     setBufferSize(80, 40);
233     setWindowPos(0, 0, 80, 40);
234
235     auto cp = GetConsoleOutputCP();
236     assert(cp == 932 || cp == 936 || cp == 949 || cp == 950);
237
238     runTest(test1);
239     runTest(test2);
240     runTest(test3);
241     runTest(test4);
242     runTest(test5);
243     runTest(test6);
244
245     return 0;
246 }