Avoid size_t types in traces.
[wine] / dlls / comctl32 / tests / mru.c
1 /*
2  * comctl32 MRU unit tests
3  *
4  * Copyright (C) 2004 Jon Griffiths <jon_p_griffiths@yahoo.com>
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winuser.h"
26 #include "winnls.h"
27 #include "winreg.h"
28 #include "commctrl.h"
29 #include "shlwapi.h"
30
31 #include "wine/test.h"
32
33 /* Keys for testing MRU functions */
34 #define REG_TEST_BASEKEYA    "Software\\Wine"
35 #define REG_TEST_BASESUBKEYA "Test"
36 #define REG_TEST_KEYA    REG_TEST_BASEKEYA "\\" REG_TEST_BASESUBKEYA
37 #define REG_TEST_SUBKEYA "MRUTest"
38 #define REG_TEST_FULLKEY REG_TEST_KEYA "\\" REG_TEST_SUBKEYA
39
40 /* Undocumented MRU structures & functions */
41 typedef struct tagCREATEMRULISTA
42 {
43     DWORD   cbSize;
44     DWORD   nMaxItems;
45     DWORD   dwFlags;
46     HKEY    hKey;
47     LPCSTR  lpszSubKey;
48     PROC    lpfnCompare;
49 } CREATEMRULISTA, *LPCREATEMRULISTA;
50
51 #define MRUF_STRING_LIST  0
52 #define MRUF_BINARY_LIST  1
53 #define MRUF_DELAYED_SAVE 2
54
55 #define LIST_SIZE 3 /* Max entries for each mru */
56
57 static CREATEMRULISTA mruA =
58 {
59     sizeof(CREATEMRULISTA),
60     LIST_SIZE,
61     0,
62     NULL,
63     REG_TEST_SUBKEYA,
64     NULL
65 };
66
67 static HMODULE hComctl32;
68 static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
69 static void   (WINAPI *pFreeMRUList)(HANDLE);
70 static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
71 static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
72 /*
73 static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
74 */
75
76
77 static BOOL create_reg_entries(void)
78 {
79     HKEY hKey = NULL;
80
81     ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
82        "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
83     if (!hKey) return FALSE;
84     RegCloseKey(hKey);
85     return TRUE;
86 }
87
88 static void delete_reg_entries(void)
89 {
90     HKEY hKey;
91
92     if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
93                       &hKey))
94         return;
95     SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
96     RegCloseKey(hKey);
97 }
98
99 static void check_reg_entries(const char *mrulist, const char**items)
100 {
101     char buff[128];
102     HKEY hKey = NULL;
103     DWORD type, size, ret;
104     unsigned int i;
105
106     ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
107        "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY);
108     if (!hKey) return;
109
110     type = REG_SZ;
111     size = sizeof(buff);
112     buff[0] = '\0';
113     ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
114
115     ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret);
116     if(ret || !buff[0]) return;
117
118     ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
119        mrulist, buff);
120     if(strcmp(buff, mrulist)) return;
121
122     for (i = 0; i < strlen(mrulist); i++)
123     {
124         char name[2];
125         name[0] = mrulist[i];
126         name[1] = '\0';
127         type = REG_SZ;
128         size = sizeof(buff);
129         buff[0] = '\0';
130         ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
131         ok(!ret && buff[0],
132            "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n",
133            i, mrulist[i], ret);
134         if(ret || !buff[0]) return;
135         ok(!strcmp(buff, items[mrulist[i]-'a']),
136            "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n",
137            i, mrulist[i], buff, items[mrulist[i] - 'a']);
138     }
139 }
140
141 static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
142 {
143     return lstrcmpiA(data1, data2);
144 }
145
146 static HANDLE create_mruA(HKEY hKey, DWORD flags, PROC cmp)
147 {
148     mruA.dwFlags = flags;
149     mruA.lpfnCompare = cmp;
150     mruA.hKey = hKey;
151
152     SetLastError(0);
153     return pCreateMRUListA(&mruA);
154 }
155
156 static void test_MRUListA(void)
157 {
158     const char *checks[LIST_SIZE+1];
159     HANDLE hMRU;
160     HKEY hKey;
161     INT iRet;
162
163     pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
164     pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
165     pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
166     pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154);
167
168     if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList)
169     {
170         skip("MRU entry points not found\n");
171         return;
172     }
173
174     if (0)
175     {
176     /* Create (NULL) - crashes native */
177     hMRU = pCreateMRUListA(NULL);
178     }
179
180     /* Create (size too small) */
181     mruA.cbSize = sizeof(mruA) - 2;
182     hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
183     ok (!hMRU && !GetLastError(),
184         "CreateMRUListA(too small) expected NULL,0 got %p,%d\n",
185         hMRU, GetLastError());
186     mruA.cbSize = sizeof(mruA);
187
188     /* Create (size too big) */
189     mruA.cbSize = sizeof(mruA) + 2;
190     hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
191     ok (!hMRU && !GetLastError(),
192         "CreateMRUListA(too big) expected NULL,0 got %p,%d\n",
193         hMRU, GetLastError());
194     mruA.cbSize = sizeof(mruA);
195
196     /* Create (NULL hKey) */
197     hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
198     ok (!hMRU && !GetLastError(),
199         "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n",
200         hMRU, GetLastError());
201
202     /* Create (NULL name) */
203     mruA.lpszSubKey = NULL;
204     hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
205     ok (!hMRU && !GetLastError(),
206         "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n",
207         hMRU, GetLastError());
208     mruA.lpszSubKey = REG_TEST_SUBKEYA;
209
210     /* Create a string MRU */
211     ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
212        "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
213     if (!hKey)
214         return;
215     hMRU = create_mruA(hKey, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
216     ok(hMRU && !GetLastError(),
217        "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n",
218        hMRU, GetLastError());
219
220     if (hMRU)
221     {
222         char buffer[255];
223         checks[0] = "Test 1";
224         checks[1] = "Test 2";
225         checks[2] = "Test 3";
226         checks[3] = "Test 4";
227
228         /* Add (NULL list) */
229         SetLastError(0);
230         iRet = pAddMRUStringA(NULL, checks[0]);
231         ok(iRet == -1 && !GetLastError(),
232            "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n",
233            iRet, GetLastError());
234
235         /* Add (NULL string) */
236         if (0)
237         {
238         /* Some native versions crash when passed NULL or fail to SetLastError()  */
239         SetLastError(0);
240         iRet = pAddMRUStringA(hMRU, NULL);
241         ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
242            "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n",
243            iRet, GetLastError());
244         }
245
246         /* Add 3 strings. Check the registry is correct after each add */
247         SetLastError(0);
248         iRet = pAddMRUStringA(hMRU, checks[0]);
249         ok(iRet == 0 && !GetLastError(),
250            "AddMRUStringA(1) expected 0,0 got %d,%d\n",
251            iRet, GetLastError());
252         check_reg_entries("a", checks);
253
254         SetLastError(0);
255         iRet = pAddMRUStringA(hMRU, checks[1]);
256         ok(iRet == 1 && !GetLastError(),
257            "AddMRUStringA(2) expected 1,0 got %d,%d\n",
258            iRet, GetLastError());
259         check_reg_entries("ba", checks);
260
261         SetLastError(0);
262         iRet = pAddMRUStringA(hMRU, checks[2]);
263         ok(iRet == 2 && !GetLastError(),
264            "AddMRUStringA(2) expected 2,0 got %d,%d\n",
265            iRet, GetLastError());
266         check_reg_entries("cba", checks);
267
268         /* Add a duplicate of the 2nd string - it should move to the front,
269          * but keep the same index in the registry.
270          */
271         SetLastError(0);
272         iRet = pAddMRUStringA(hMRU, checks[1]);
273         ok(iRet == 1 && !GetLastError(),
274            "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n",
275            iRet, GetLastError());
276         check_reg_entries("bca", checks);
277
278         /* Add a new string - replaces the oldest string + moves to the front */
279         SetLastError(0);
280         iRet = pAddMRUStringA(hMRU, checks[3]);
281         ok(iRet == 0 && !GetLastError(),
282            "AddMRUStringA(add new) expected 0,0 got %d,%d\n",
283            iRet, GetLastError());
284         checks[0] = checks[3];
285         check_reg_entries("abc", checks);
286
287         /* NULL buffer = get list size */
288         iRet = pEnumMRUList(hMRU, 0, NULL, 0);
289         ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
290
291         /* negative item pos = get list size */
292         iRet = pEnumMRUList(hMRU, -1, NULL, 0);
293         ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
294
295         /* negative item pos = get list size */
296         iRet = pEnumMRUList(hMRU, -5, NULL, 0);
297         ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
298
299         /* negative item pos = get list size */
300         iRet = pEnumMRUList(hMRU, -1, buffer, 255);
301         ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
302
303         /* negative item pos = get list size */
304         iRet = pEnumMRUList(hMRU, -5, buffer, 255);
305         ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
306
307         /* check entry 0 */
308         buffer[0] = 0;
309         iRet = pEnumMRUList(hMRU, 0, buffer, 255);
310         todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
311         ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer);
312
313         /* check entry 0 with a too small buffer */
314         buffer[0] = 0;   /* overwritten with 'T' */
315         buffer[1] = 'A'; /* overwritten with 0   */
316         buffer[2] = 'A'; /* unchanged */
317         buffer[3] = 0;   /* unchanged */
318         iRet = pEnumMRUList(hMRU, 0, buffer, 2);
319         todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
320         todo_wine ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer);
321         /* make sure space after buffer has old values */
322         ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]);
323
324         /* check entry 1 */
325         buffer[0] = 0;
326         iRet = pEnumMRUList(hMRU, 1, buffer, 255);
327         todo_wine ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet);
328         ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer);
329
330         /* check entry 2 */
331         buffer[0] = 0;
332         iRet = pEnumMRUList(hMRU, 2, buffer, 255);
333         todo_wine ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet);
334         ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer);
335
336         /* check out of bounds entry 3 */
337         strcpy(buffer, "dummy");
338         iRet = pEnumMRUList(hMRU, 3, buffer, 255);
339         ok(iRet == -1, "EnumMRUList expected %d, got %d\n", -1, iRet);
340         ok(strcmp(buffer, "dummy") == 0, "EnumMRUList expected unchanged buffer %s, got %s\n", "dummy", buffer);
341
342         /* Finished with this MRU */
343         pFreeMRUList(hMRU);
344     }
345
346     /* Free (NULL list) - Doesn't crash */
347     pFreeMRUList(NULL);
348 }
349
350 START_TEST(mru)
351 {
352     hComctl32 = GetModuleHandleA("comctl32.dll");
353
354     delete_reg_entries();
355     if (!create_reg_entries())
356         return;
357
358     test_MRUListA();
359
360     delete_reg_entries();
361 }