aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc
blob: 7210d410323e75238b4a8a51084d835ff6053d45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Demonstrates how U+30FC is sometimes handled as a single-width character
// when it should be handled as a double-width character.
//
// It only runs on computers where 932 is a valid code page.  Set the system
// local to "Japanese (Japan)" to ensure this.
//
// The problem seems to happen when U+30FC is printed in a console using the
// Lucida Console font, and only when that font is at certain sizes.
//

#include <windows.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "TestUtil.cc"

#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))

static void setFont(const wchar_t *faceName, int pxSize) {
    CONSOLE_FONT_INFOEX infoex = {0};
    infoex.cbSize = sizeof(infoex);
    infoex.dwFontSize.Y = pxSize;
    wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName));
    BOOL ret = SetCurrentConsoleFontEx(
        GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex);
    assert(ret);
}

static bool performTest(const wchar_t testChar) {
    const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(conout, 7);

    system("cls");
    DWORD actual = 0;
    BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL);
    assert(ret && actual == 1);

    CHAR_INFO verify[2];
    COORD bufSize = {2, 1};
    COORD bufCoord = {0, 0};
    const SMALL_RECT readRegion = {0, 0, 1, 0};
    SMALL_RECT actualRegion = readRegion;
    ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion);
    assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion)));
    assert(verify[0].Char.UnicodeChar == testChar);

    if (verify[1].Char.UnicodeChar == testChar) {
        // Typical double-width behavior with a TrueType font.  Pass.
        assert(verify[0].Attributes == 0x107);
        assert(verify[1].Attributes == 0x207);
        return true;
    } else if (verify[1].Char.UnicodeChar == 0) {
        // Typical double-width behavior with a Raster Font.  Pass.
        assert(verify[0].Attributes == 7);
        assert(verify[1].Attributes == 0);
        return true;
    } else if (verify[1].Char.UnicodeChar == L' ') {
        // Single-width behavior.  Fail.
        assert(verify[0].Attributes == 7);
        assert(verify[1].Attributes == 7);
        return false;
    } else {
        // Unexpected output.
        assert(false);
    }
}

int main(int argc, char *argv[]) {
    setlocale(LC_ALL, "");
    if (argc == 1) {
        startChildProcess(L"CHILD");
        return 0;
    }

    assert(SetConsoleCP(932));
    assert(SetConsoleOutputCP(932));

    const wchar_t testChar = 0x30FC;
    const wchar_t *const faceNames[] = {
        L"Lucida Console",
        L"Consolas",
        L"MS ゴシック",
    };

    trace("Test started");

    for (auto faceName : faceNames) {
        for (int px = 1; px <= 50; ++px) {
            setFont(faceName, px);
            if (!performTest(testChar)) {
                trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px);
            }
        }
    }

    trace("Test complete");
    return 0;
}