Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / mlang / tests / mlang.c
1 /*
2  * Unit test suite for MLANG APIs.
3  *
4  * Copyright 2004 Dmitry Timoshkov
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "mlang.h"
29
30 #include "wine/test.h"
31 #include "wine/debug.h"
32
33 #ifndef CP_UNICODE
34 #define CP_UNICODE 1200
35 #endif
36
37 /*#define DUMP_CP_INFO*/
38
39 #define TRACE_2 OutputDebugStringA
40
41 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
42 {
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};
46     char bufA[256];
47     WCHAR bufW[256];
48     UINT lenA, lenW;
49     HRESULT ret;
50
51     /* IMultiLanguage2_ConvertStringToUnicode tests */
52
53     memset(bufW, 'x', sizeof(bufW));
54     lenA = 0;
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);
61
62     memset(bufW, 'x', sizeof(bufW));
63     lenA = -1;
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");
73
74     memset(bufW, 'x', sizeof(bufW));
75     lenA = -1;
76     lenW = 5;
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");
83
84     memset(bufW, 'x', sizeof(bufW));
85     lenA = -1;
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");
95
96     /* IMultiLanguage2_ConvertStringFromUnicode tests */
97
98     memset(bufA, 'x', sizeof(bufA));
99     lenW = 0;
100     lenA = 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);
106
107     memset(bufA, 'x', sizeof(bufA));
108     lenW = -1;
109     lenA = 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");
118
119     memset(bufA, 'x', sizeof(bufA));
120     lenW = -1;
121     lenA = 5;
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");
128
129     memset(bufA, 'x', sizeof(bufA));
130     lenW = -1;
131     lenA = 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");
141 }
142
143 static void inline cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
144 {
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);
155 }
156
157 #ifdef DUMP_CP_INFO
158 static const char *dump_mime_flags(DWORD flags)
159 {
160     static char buf[1024];
161
162     buf[0] = 0;
163
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");
177
178     return buf;
179 }
180 #endif
181
182 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
183 {
184     IEnumCodePage *iEnumCP = NULL;
185     MIMECPINFO *cpinfo;
186     MIMECPINFO cpinfo2;
187     HRESULT ret;
188     ULONG i, n;
189     UINT total;
190
191     total = 0;
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);
195
196     trace("total mlang supported codepages %u\n", total);
197
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);
202
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);
206     n = 65536;
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);
213
214     cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2);
215
216     n = 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);
221
222     n = total * 2;
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);
226
227     trace("flags %08lx, enumerated codepages %lu\n", flags, n);
228
229     if (!flags)
230     {
231         ok(n == total, "IEnumCodePage_Next: expected %u, got %lu", total, n);
232
233         flags = MIMECONTF_MIME_LATEST;
234     }
235
236     total = n;
237
238     for (i = 0; i < n; i++)
239     {
240         CPINFOEXA cpinfoex;
241         CHARSETINFO csi;
242 #ifdef DUMP_CP_INFO
243         trace("MIMECPINFO #%lu:\n"
244               "dwFlags %08lx %s\n"
245               "uiCodePage %u\n"
246               "uiFamilyCodePage %u\n"
247               "wszDescription %s\n"
248               "wszWebCharset %s\n"
249               "wszHeaderCharset %s\n"
250               "wszBodyCharset %s\n"
251               "wszFixedWidthFont %s\n"
252               "wszProportionalFont %s\n"
253               "bGDICharset %d\n\n",
254               i,
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);
265 #endif
266         ok(cpinfo[i].dwFlags & flags, "enumerated flags %08lx do not include requested %08lx\n", cpinfo[i].dwFlags, flags);
267
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);
270         else
271             trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
272
273         if (GetCPInfoExA(cpinfo[i].uiCodePage, 0, &cpinfoex))
274             trace("CodePage %u name: %s\n", cpinfo[i].uiCodePage, cpinfoex.CodePageName);
275         else
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);
279         else
280             trace("GetCPInfoExA failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
281
282         /* Win95 does not support UTF-7 */
283         if (cpinfo[i].uiCodePage == CP_UTF7) continue;
284
285         /* support files for some codepages might be not installed, or
286          * the codepage is just an alias.
287          */
288         if (IsValidCodePage(cpinfo[i].uiCodePage))
289         {
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);
296
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);
303         }
304         else
305             trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage);
306
307         trace("---\n");
308     }
309
310     /* now IEnumCodePage_Next should fail, since pointer is at the end */
311     n = 1;
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);
314
315     ret = IEnumCodePage_Reset(iEnumCP);
316     ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08lx\n", ret);
317     n = 0;
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);
321
322 #if 0
323     /* Due to a bug in MS' implementation of IEnumCodePage_Skip
324      * it's not used here.
325      */
326     ret = IEnumCodePage_Skip(iEnumCP, 1);
327     ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08lx\n", ret);
328 #endif
329     for (i = 0; i < total - 1; i++)
330     {
331         n = 0;
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);
335     }
336
337     HeapFree(GetProcessHeap(), 0, cpinfo);
338     IEnumCodePage_Release(iEnumCP);
339 }
340
341 START_TEST(mlang)
342 {
343     IMultiLanguage2 *iML2 = NULL;
344     HRESULT ret;
345
346     CoInitialize(NULL);
347     TRACE_2("Call CoCreateInstance\n");
348     ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
349                            &IID_IMultiLanguage2, (void **)&iML2);
350
351     trace("ret = %08lx, MultiLanguage2 iML2 = %p\n", ret, iML2);
352     if (ret != S_OK || !iML2) return;
353
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);*/
361
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);
368
369     test_multibyte_to_unicode_translations(iML2);
370
371     IMultiLanguage2_Release(iML2);
372
373     CoUninitialize();
374 }