1 // Demonstrates how U+30FC is sometimes handled as a single-width character
2 // when it should be handled as a double-width character.
4 // It only runs on computers where 932 is a valid code page. Set the system
5 // local to "Japanese (Japan)" to ensure this.
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.
18 #include "TestUtil.cc"
20 #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
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);
32 static bool performTest(const wchar_t testChar) {
33 const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
35 SetConsoleTextAttribute(conout, 7);
39 BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL);
40 assert(ret && actual == 1);
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);
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);
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);
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);
72 int main(int argc, char *argv[]) {
73 setlocale(LC_ALL, "");
75 startChildProcess(L"CHILD");
79 assert(SetConsoleCP(932));
80 assert(SetConsoleOutputCP(932));
82 const wchar_t testChar = 0x30FC;
83 const wchar_t *const faceNames[] = {
89 trace("Test started");
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);
100 trace("Test complete");