2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for MultiByteToWideChar
5 * PROGRAMMERS: Mike "tamlin" Nordell
6 * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11 /* NOTE: Tested on Win10. We follow Win10 in this function.
12 Win10 might alter its design in future. */
14 /* TODO: Russian, French, Korean etc. codepages */
16 #define CP932 932 /* Japanese Shift_JIS (SJIS) codepage */
18 /* "Japanese" in Japanese UTF-8 */
19 static const char UTF8_Japanese
[] = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E";
20 /* "Japanese" in Japanese Shift_JIS */
21 static const char SJIS_Japanese
[] = "\x93\xFA\x96\x7B\x8C\xEA";
36 WCHAR CheckDest
[MAX_BUFFER
];
41 static const ENTRY Entries
[] =
44 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "a", 1 },
45 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "a", 2 },
46 { __LINE__
, 2, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, "a", 2 },
48 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "a", -1 },
49 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "a", -2 },
50 { __LINE__
, 2, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, "a", -1 },
51 { __LINE__
, 2, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, "a", -3 },
53 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "a", 1, 1, {'a', 0x7F7F}, 2 },
54 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "a", 2, 4, {'a', 0, 0x7F7F}, 3 },
55 { __LINE__
, 2, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, "a", 2, 4, {'a', 0, 0x7F7F}, 3 },
57 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "a", 2, 1, {'a', 0x7F7F}, 2 },
58 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "a", 2, 1, {'a', 0x7F7F}, 2 },
59 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "a", 2, 1, {'a', 0x7F7F}, 2 },
61 { __LINE__
, 0, ERROR_INVALID_PARAMETER
, CP_UTF8
, 0, "", 1, 1, { 0x7F7F }, 1, TRUE
},
62 { __LINE__
, 0, ERROR_INVALID_PARAMETER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "", 1, 1, { 0x7F7F }, 1, TRUE
},
63 /* invalid UTF-8 sequences without buffer */
64 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xC0", 2 },
65 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xC0\xC0\x80", 4 },
66 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xE0\xC0", 3 },
67 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xE0\x20\xC0", 4 },
68 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0", 2 },
69 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0\xC0\x80", 4 },
70 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\xC0", 3 },
71 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\x20\xC0", 4 },
72 /* invalid UTF-8 sequences with buffer */
73 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xC0", 2, 4, {0xFFFD, 0, 0x7F7F}, 3},
74 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xC0\xC0\x80", 4, 5, {0xFFFD, 0xFFFD, 0xFFFD, 0, 0x7F7F}, 5 },
75 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xE0\xC0", 3, 4, {0xFFFD, 0xFFFD, 0, 0x7F7F}, 4 },
76 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xE0\x20\xC0", 4, 5, {0xFFFD, 0x0020, 0xFFFD, 0, 0x7F7F}, 5 },
77 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0", 2, 4, {0xFFFD, 0, 0x7F7F}, 3 },
78 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0\xC0\x80", 4, 5, {0xFFFD, 0xFFFD, 0xFFFD, 0, 0x7F7F}, 5 },
79 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\xC0", 3, 4, {0xFFFD, 0xFFFD, 0, 0x7F7F}, 4 },
80 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\x20\xC0", 4, 5, {0xFFFD, 0x0020, 0xFFFD, 0, 0x7F7F}, 5 },
81 /* invalid UTF-8 sequences with short buffer */
82 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "\xC0", 2, 1, {0xFFFD, 0x7F7F}, 2},
83 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "\xC0\xC0\x80", 4, 1, {0xFFFD, 0x7F7F}, 2 },
84 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "\xE0\xC0", 3, 1, {0xFFFD, 0x7F7F}, 2 },
85 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "\xE0\x20\xC0", 4, 1, {0xFFFD, 0x7F7F}, 2 },
86 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0", 2, 1, {0xFFFD, 0x7F7F}, 2 },
87 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xC0\xC0\x80", 4, 1, {0xFFFD, 0x7F7F}, 2 },
88 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\xC0", 3, 1, {0xFFFD, 0x7F7F}, 2 },
89 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, "\xE0\x20\xC0", 4, 1, {0xFFFD, 0x7F7F}, 2 },
90 /* Japanese UTF-8 without buffer */
91 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, UTF8_Japanese
, sizeof(UTF8_Japanese
) },
92 { __LINE__
, 4, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, UTF8_Japanese
, sizeof(UTF8_Japanese
) },
93 /* Japanese UTF-8 with buffer */
94 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, UTF8_Japanese
, sizeof(UTF8_Japanese
), 4, {0x65E5, 0x672C, 0x8A9E, 0, 0x7F7F}, 5 },
95 { __LINE__
, 4, 0xBEAF, CP_UTF8
, MB_ERR_INVALID_CHARS
, UTF8_Japanese
, sizeof(UTF8_Japanese
), 4, {0x65E5, 0x672C, 0x8A9E, 0, 0x7F7F}, 5 },
96 /* Japanese UTF-8 with short buffer */
97 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, UTF8_Japanese
, sizeof(UTF8_Japanese
), 1, {0x65E5, 0x7F7F}, 2 },
98 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, MB_ERR_INVALID_CHARS
, UTF8_Japanese
, sizeof(UTF8_Japanese
), 1, {0x65E5, 0x7F7F}, 2 },
99 /* Japanese UTF-8 truncated source */
100 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, UTF8_Japanese
, 1, 4, {0xFFFD, 0x7F7F}, 2 },
101 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP_UTF8
, MB_ERR_INVALID_CHARS
, UTF8_Japanese
, 1, 4, {0xFFFD, 0x7F7F}, 2 },
102 /* Japanese CP932 without buffer */
103 { __LINE__
, 4, 0xBEAF, CP932
, 0, SJIS_Japanese
, sizeof(SJIS_Japanese
) },
104 { __LINE__
, 4, 0xBEAF, CP932
, MB_ERR_INVALID_CHARS
, SJIS_Japanese
, sizeof(SJIS_Japanese
) },
105 /* Japanese CP932 with buffer */
106 { __LINE__
, 4, 0xBEAF, CP932
, 0, SJIS_Japanese
, sizeof(SJIS_Japanese
), 4, {0x65E5, 0x672C, 0x8A9E, 0, 0x7F7F}, 5 },
107 { __LINE__
, 4, 0xBEAF, CP932
, MB_ERR_INVALID_CHARS
, SJIS_Japanese
, sizeof(SJIS_Japanese
), 4, {0x65E5, 0x672C, 0x8A9E, 0, 0x7F7F}, 5 },
108 /* Japanese CP932 with short buffer */
109 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP932
, 0, SJIS_Japanese
, sizeof(SJIS_Japanese
), 1, {0x65E5, 0x7F7F}, 2 },
110 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP932
, MB_ERR_INVALID_CHARS
, SJIS_Japanese
, sizeof(SJIS_Japanese
), 1, {0x65E5, 0x7F7F}, 2 },
111 /* Japanese CP932 truncated source */
112 { __LINE__
, 1, 0xBEAF, CP932
, 0, SJIS_Japanese
, 1, 4, {0x30FB, 0x7F7F}, 2 },
113 { __LINE__
, 0, ERROR_NO_UNICODE_TRANSLATION
, CP932
, MB_ERR_INVALID_CHARS
, SJIS_Japanese
, 1, 4, {0x7F7F, 0x7F7F}, 2 },
114 /* invalid 5-byte UTF-8 sequences */
115 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 1, 8, {0xFFFD, 0x7F7F}, 2 },
116 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 2, 8, {0xFFFD, 0xFFFD, 0x7F7F}, 3 },
117 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 3, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 4 },
118 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 4, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 5 },
119 { __LINE__
, 5, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 5, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 6 },
120 { __LINE__
, 6, 0xBEAF, CP_UTF8
, 0, "\xF8\xA3\xA3\xA3\xA3", 6, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0}, 6 },
121 /* invalid 6-byte UTF-8 sequences */
122 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 1, 8, {0xFFFD, 0x7F7F}, 2 },
123 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 2, 8, {0xFFFD, 0xFFFD, 0x7F7F}, 3 },
124 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 3, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 4 },
125 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 4, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 5 },
126 { __LINE__
, 5, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 5, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 6 },
127 { __LINE__
, 6, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 6, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 7 },
128 { __LINE__
, 7, 0xBEAF, CP_UTF8
, 0, "\xFC\xA3\xA3\xA3\xA3\xA3", 7, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0}, 7 },
129 /* invalid 7-byte UTF-8 sequences */
130 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 1, 8, {0xFFFD, 0x7F7F}, 2 },
131 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 2, 8, {0xFFFD, 0xFFFD, 0x7F7F}, 3 },
132 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 3, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 4 },
133 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 4, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 5 },
134 { __LINE__
, 5, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 5, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 6 },
135 { __LINE__
, 6, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 6, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 7 },
136 { __LINE__
, 7, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 7, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 8 },
137 { __LINE__
, 8, 0xBEAF, CP_UTF8
, 0, "\xFE\xA3\xA3\xA3\xA3\xA3\xA3", 8, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0}, 8 },
138 /* invalid UTF-8 sequences */
139 { __LINE__
, 1, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 1, 8, {0xFFFD, 0x7F7F}, 2 },
140 { __LINE__
, 2, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 2, 8, {0xFFFD, 0xFFFD, 0x7F7F}, 3 },
141 { __LINE__
, 3, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 3, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 4 },
142 { __LINE__
, 4, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 4, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 5 },
143 { __LINE__
, 5, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 5, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 6 },
144 { __LINE__
, 6, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 6, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 7 },
145 { __LINE__
, 7, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 7, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 8 },
146 { __LINE__
, 8, 0xBEAF, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 8, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 9 },
147 { __LINE__
, 0, ERROR_INSUFFICIENT_BUFFER
, CP_UTF8
, 0, "\xFF\xA3\xA3\xA3\xA3\xA3\xA3\xA3", 9, 8, {0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x7F7F}, 9 },
150 static void TestEntry(const ENTRY
*pEntry
)
153 WCHAR Buffer
[MAX_BUFFER
];
156 FillMemory(Buffer
, sizeof(Buffer
), 0x7F);
157 SetLastError(0xBEAF);
159 if (pEntry
->DestLen
== 0)
162 ret
= MultiByteToWideChar(pEntry
->CodePage
, pEntry
->Flags
, pEntry
->Src
,
163 pEntry
->SrcLen
, NULL
, 0);
167 ok(pEntry
->DestLen
>= pEntry
->CheckLen
- 1,
168 "Line %d: DestLen was shorter than (CheckLen - 1)\n", pEntry
->LineNo
);
170 if (pEntry
->SamePointer
)
172 /* src ptr == dest ptr */
173 ret
= MultiByteToWideChar(pEntry
->CodePage
, pEntry
->Flags
,
174 (const char *)Buffer
, pEntry
->SrcLen
,
175 Buffer
, pEntry
->DestLen
);
179 /* src ptr != dest ptr */
180 ret
= MultiByteToWideChar(pEntry
->CodePage
, pEntry
->Flags
,
181 pEntry
->Src
, pEntry
->SrcLen
,
182 Buffer
, pEntry
->DestLen
);
186 Error
= GetLastError();
189 ok(ret
== pEntry
->Return
, "Line %d: ret expected %d, got %d\n",
190 pEntry
->LineNo
, pEntry
->Return
, ret
);
192 /* check error code */
193 ok(Error
== pEntry
->Error
,
194 "Line %d: Wrong last error. Expected %lu, got %lu\n",
195 pEntry
->LineNo
, pEntry
->Error
, Error
);
200 for (i
= 0; i
< pEntry
->CheckLen
; ++i
)
202 ok(Buffer
[i
] == pEntry
->CheckDest
[i
], "Line %d: Buffer[%d] expected %d, got %d\n",
203 pEntry
->LineNo
, i
, pEntry
->CheckDest
[i
], Buffer
[i
]);
208 typedef NTSTATUS (WINAPI
* RTLGETVERSION
)(PRTL_OSVERSIONINFOW
);
210 static RTL_OSVERSIONINFOW
*GetRealOSVersion(void)
212 static RTL_OSVERSIONINFOW osvi
= { 0 };
213 RTL_OSVERSIONINFOW
*ptr
= NULL
;
214 HINSTANCE hNTDLL
= LoadLibraryW(L
"ntdll.dll");
218 fn
= (RTLGETVERSION
)GetProcAddress(hNTDLL
, "RtlGetVersion");
221 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
222 if (fn(&osvi
) == STATUS_SUCCESS
)
232 static BOOL
IsWin10Plus(void)
234 RTL_OSVERSIONINFOW
*info
= GetRealOSVersion();
238 return info
->dwMajorVersion
>= 10;
241 static BOOL
IsReactOS(void)
243 WCHAR szWinDir
[MAX_PATH
];
244 GetWindowsDirectoryW(szWinDir
, _countof(szWinDir
));
245 return (wcsstr(szWinDir
, L
"ReactOS") != NULL
);
248 START_TEST(MultiByteToWideChar
)
252 if (!IsWin10Plus() && !IsReactOS())
254 trace("This test is designed for Windows 10+ and ReactOS.\n"
255 "It is expected to report some failures on older Windows versions.\n");
262 for (i
= 0; i
< _countof(Entries
); ++i
)
264 TestEntry(&Entries
[i
]);