2 * Unit test suite for MLANG APIs.
4 * Copyright 2004 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/test.h"
31 #include "wine/debug.h"
34 #define CP_UNICODE 1200
37 /*#define DUMP_CP_INFO*/
39 #define TRACE_2 OutputDebugStringA
41 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
43 /* these APIs are broken regarding constness of the input buffer */
44 char stringA[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
45 WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
51 /* IMultiLanguage2_ConvertStringToUnicode tests */
53 memset(bufW, 'x', sizeof(bufW));
55 lenW = sizeof(bufW)/sizeof(bufW[0]);
56 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
57 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
58 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08lx\n", ret);
59 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
60 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
62 memset(bufW, 'x', sizeof(bufW));
64 lenW = sizeof(bufW)/sizeof(bufW[0]);
65 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
66 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
67 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08lx\n", ret);
68 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
69 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
70 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
71 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
72 ok(!lstrcmpW(bufW, stringW), "bufW/stringW mismatch\n");
74 memset(bufW, 'x', sizeof(bufW));
77 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
78 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
79 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08lx\n", ret);
80 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
81 /* still has to do partial conversion */
82 ok(!memcmp(bufW, stringW, 5 * sizeof(WCHAR)), "bufW/stringW mismatch\n");
84 memset(bufW, 'x', sizeof(bufW));
86 lenW = sizeof(bufW)/sizeof(bufW[0]);
87 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
88 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW);
89 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08lx\n", ret);
90 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
91 ok(lenW == lstrlenW(stringW)/sizeof(WCHAR), "expected lenW %u, got %u\n", lstrlenW(stringW)/sizeof(WCHAR), lenW);
92 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
93 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
94 ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n");
96 /* IMultiLanguage2_ConvertStringFromUnicode tests */
98 memset(bufA, 'x', sizeof(bufA));
101 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
102 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
103 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08lx\n", ret);
104 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
105 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
107 memset(bufA, 'x', sizeof(bufA));
110 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
111 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
112 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08lx\n", ret);
113 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
114 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
115 ok(bufA[lenA] != 0, "buf should not be 0 terminated\n");
116 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
117 ok(!lstrcmpA(bufA, stringA), "bufA/stringA mismatch\n");
119 memset(bufA, 'x', sizeof(bufA));
122 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
123 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
124 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08lx\n", ret);
125 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
126 /* still has to do partial conversion */
127 ok(!memcmp(bufA, stringA, 5), "bufW/stringW mismatch\n");
129 memset(bufA, 'x', sizeof(bufA));
132 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
133 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA);
134 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08lx\n", ret);
135 ok(lenA == lstrlenA(stringA) * sizeof(WCHAR), "expected lenA %u, got %u\n", lstrlenA(stringA) * sizeof(WCHAR), lenA);
136 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
137 ok(bufA[lenA] != 0 && bufA[lenA+1] != 0, "buf should not be 0 terminated\n");
138 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
139 bufA[lenA+1] = 0; /* sizeof(WCHAR) */
140 ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n");
143 static void inline cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
145 ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08lx != %08lx\n", cpinfo1->dwFlags, cpinfo2->dwFlags);
146 ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage);
147 ok(cpinfo1->uiFamilyCodePage == cpinfo2->uiFamilyCodePage, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1->uiFamilyCodePage, cpinfo2->uiFamilyCodePage);
148 ok(!lstrcmpW(cpinfo1->wszDescription, cpinfo2->wszDescription), "wszDescription mismatch\n");
149 ok(!lstrcmpW(cpinfo1->wszWebCharset, cpinfo2->wszWebCharset), "wszWebCharset mismatch\n");
150 ok(!lstrcmpW(cpinfo1->wszHeaderCharset, cpinfo2->wszHeaderCharset), "wszHeaderCharset mismatch\n");
151 ok(!lstrcmpW(cpinfo1->wszBodyCharset, cpinfo2->wszBodyCharset), "wszBodyCharset mismatch\n");
152 ok(!lstrcmpW(cpinfo1->wszFixedWidthFont, cpinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
153 ok(!lstrcmpW(cpinfo1->wszProportionalFont, cpinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
154 ok(cpinfo1->bGDICharset == cpinfo2->bGDICharset, "bGDICharset mismatch: %d != %d\n", cpinfo1->bGDICharset, cpinfo2->bGDICharset);
158 static const char *dump_mime_flags(DWORD flags)
160 static char buf[1024];
164 if (flags & MIMECONTF_MAILNEWS) strcat(buf, " MIMECONTF_MAILNEWS");
165 if (flags & MIMECONTF_BROWSER) strcat(buf, " MIMECONTF_BROWSER");
166 if (flags & MIMECONTF_MINIMAL) strcat(buf, " MIMECONTF_MINIMAL");
167 if (flags & MIMECONTF_IMPORT) strcat(buf, " MIMECONTF_IMPORT");
168 if (flags & MIMECONTF_SAVABLE_MAILNEWS) strcat(buf, " MIMECONTF_SAVABLE_MAILNEWS");
169 if (flags & MIMECONTF_SAVABLE_BROWSER) strcat(buf, " MIMECONTF_SAVABLE_BROWSER");
170 if (flags & MIMECONTF_EXPORT) strcat(buf, " MIMECONTF_EXPORT");
171 if (flags & MIMECONTF_PRIVCONVERTER) strcat(buf, " MIMECONTF_PRIVCONVERTER");
172 if (flags & MIMECONTF_VALID) strcat(buf, " MIMECONTF_VALID");
173 if (flags & MIMECONTF_VALID_NLS) strcat(buf, " MIMECONTF_VALID_NLS");
174 if (flags & MIMECONTF_MIME_IE4) strcat(buf, " MIMECONTF_MIME_IE4");
175 if (flags & MIMECONTF_MIME_LATEST) strcat(buf, " MIMECONTF_MIME_LATEST");
176 if (flags & MIMECONTF_MIME_REGISTRY) strcat(buf, " MIMECONTF_MIME_REGISTRY");
182 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
184 IEnumCodePage *iEnumCP = NULL;
192 TRACE_2("Call IMultiLanguage2_GetNumberOfCodePageInfo\n");
193 ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total);
194 ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08lx/%u\n", ret, total);
196 trace("total mlang supported codepages %u\n", total);
198 TRACE_2("Call IMultiLanguage2_EnumCodePages\n");
199 ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP);
200 trace("IMultiLanguage2_EnumCodePages = %08lx, iEnumCP = %p\n", ret, iEnumCP);
201 ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08lx/%p\n", ret, iEnumCP);
203 TRACE_2("Call IEnumCodePage_Reset\n");
204 ret = IEnumCodePage_Reset(iEnumCP);
205 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08lx\n", ret);
207 TRACE_2("Call IEnumCodePage_Next\n");
208 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n);
209 ok(n == 0 && ret == S_FALSE, "IEnumCodePage_Next: expected 0/S_FALSE, got %lu/%08lx\n", n, ret);
210 TRACE_2("Call IEnumCodePage_Next\n");
211 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL);
212 ok(ret == S_FALSE, "IEnumCodePage_Next: expected S_FALSE, got %08lx\n", ret);
214 cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2);
217 TRACE_2("Call IEnumCodePage_Next\n");
218 ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n);
219 trace("IEnumCodePage_Next = %08lx, n = %lu\n", ret, n);
220 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08lx/%lu\n", ret, n);
223 TRACE_2("Call IEnumCodePage_Next\n");
224 ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n);
225 ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK, got %08lx/%lu\n", ret, n);
227 trace("flags %08lx, enumerated codepages %lu\n", flags, n);
231 ok(n == total, "IEnumCodePage_Next: expected %u, got %lu", total, n);
233 flags = MIMECONTF_MIME_LATEST;
238 for (i = 0; i < n; i++)
243 trace("MIMECPINFO #%lu:\n"
246 "uiFamilyCodePage %u\n"
247 "wszDescription %s\n"
249 "wszHeaderCharset %s\n"
250 "wszBodyCharset %s\n"
251 "wszFixedWidthFont %s\n"
252 "wszProportionalFont %s\n"
253 "bGDICharset %d\n\n",
255 cpinfo[i].dwFlags, dump_mime_flags(cpinfo[i].dwFlags),
256 cpinfo[i].uiCodePage,
257 cpinfo[i].uiFamilyCodePage,
258 wine_dbgstr_w(cpinfo[i].wszDescription),
259 wine_dbgstr_w(cpinfo[i].wszWebCharset),
260 wine_dbgstr_w(cpinfo[i].wszHeaderCharset),
261 wine_dbgstr_w(cpinfo[i].wszBodyCharset),
262 wine_dbgstr_w(cpinfo[i].wszFixedWidthFont),
263 wine_dbgstr_w(cpinfo[i].wszProportionalFont),
264 cpinfo[i].bGDICharset);
266 ok(cpinfo[i].dwFlags & flags, "enumerated flags %08lx do not include requested %08lx\n", cpinfo[i].dwFlags, flags);
268 if (TranslateCharsetInfo((DWORD *)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE))
269 ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset);
271 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
273 if (GetCPInfoExA(cpinfo[i].uiCodePage, 0, &cpinfoex))
274 trace("CodePage %u name: %s\n", cpinfo[i].uiCodePage, cpinfoex.CodePageName);
276 trace("GetCPInfoExA failed for cp %u\n", cpinfo[i].uiCodePage);
277 if (GetCPInfoExA(cpinfo[i].uiFamilyCodePage, 0, &cpinfoex))
278 trace("CodePage %u name: %s\n", cpinfo[i].uiFamilyCodePage, cpinfoex.CodePageName);
280 trace("GetCPInfoExA failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
282 /* Win95 does not support UTF-7 */
283 if (cpinfo[i].uiCodePage == CP_UTF7) continue;
285 /* support files for some codepages might be not installed, or
286 * the codepage is just an alias.
288 if (IsValidCodePage(cpinfo[i].uiCodePage))
290 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
291 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE);
292 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08lx\n", cpinfo[i].uiCodePage, ret);
293 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
294 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage);
295 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08lx\n", cpinfo[i].uiCodePage, ret);
297 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
298 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
299 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08lx\n", cpinfo[i].uiCodePage, ret);
300 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
301 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage);
302 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08lx\n", cpinfo[i].uiCodePage, ret);
305 trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage);
310 /* now IEnumCodePage_Next should fail, since pointer is at the end */
312 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
313 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_OK/0, got %08lx/%lu\n", ret, n);
315 ret = IEnumCodePage_Reset(iEnumCP);
316 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08lx\n", ret);
318 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
319 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 2/S_OK, got %lu/%08lx\n", n, ret);
320 cpinfo_cmp(&cpinfo[0], &cpinfo2);
323 /* Due to a bug in MS' implementation of IEnumCodePage_Skip
324 * it's not used here.
326 ret = IEnumCodePage_Skip(iEnumCP, 1);
327 ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08lx\n", ret);
329 for (i = 0; i < total - 1; i++)
332 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
333 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %lu/%08lx\n", n, ret);
334 cpinfo_cmp(&cpinfo[i + 1], &cpinfo2);
337 HeapFree(GetProcessHeap(), 0, cpinfo);
338 IEnumCodePage_Release(iEnumCP);
343 IMultiLanguage2 *iML2 = NULL;
347 TRACE_2("Call CoCreateInstance\n");
348 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
349 &IID_IMultiLanguage2, (void **)&iML2);
351 trace("ret = %08lx, MultiLanguage2 iML2 = %p\n", ret, iML2);
352 if (ret != S_OK || !iML2) return;
354 test_EnumCodePages(iML2, 0);
355 test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST);
356 test_EnumCodePages(iML2, MIMECONTF_BROWSER);
357 test_EnumCodePages(iML2, MIMECONTF_MINIMAL);
358 test_EnumCodePages(iML2, MIMECONTF_VALID);
359 /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
360 /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
362 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
363 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE);
364 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08lx\n", ret);
365 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
366 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8);
367 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08lx\n", ret);
369 test_multibyte_to_unicode_translations(iML2);
371 IMultiLanguage2_Release(iML2);