msi: Only insert entries into listbox if property value matches.
[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 /*
72 static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
73 static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
74 */
75
76 static BOOL create_reg_entries(void)
77 {
78     HKEY hKey = NULL;
79
80     ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
81        "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
82     if (!hKey) return FALSE;
83     RegCloseKey(hKey);
84     return TRUE;
85 }
86
87 static void delete_reg_entries(void)
88 {
89     HKEY hKey;
90
91     if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
92                       &hKey))
93         return;
94     SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
95     RegCloseKey(hKey);
96 }
97
98 static void check_reg_entries(const char *mrulist, const char**items)
99 {
100     char buff[128];
101     HKEY hKey = NULL;
102     DWORD type, size, ret;
103     unsigned int i;
104
105     ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
106        "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY);
107     if (!hKey) return;
108
109     type = REG_SZ;
110     size = sizeof(buff);
111     buff[0] = '\0';
112     ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
113
114     ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret);
115     if(ret || !buff[0]) return;
116
117     ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
118        mrulist, buff);
119     if(strcmp(buff, mrulist)) return;
120
121     for (i = 0; i < strlen(mrulist); i++)
122     {
123         char name[2];
124         name[0] = mrulist[i];
125         name[1] = '\0';
126         type = REG_SZ;
127         size = sizeof(buff);
128         buff[0] = '\0';
129         ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
130         ok(!ret && buff[0],
131            "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n",
132            i, mrulist[i], ret);
133         if(ret || !buff[0]) return;
134         ok(!strcmp(buff, items[mrulist[i]-'a']),
135            "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n",
136            i, mrulist[i], buff, items[mrulist[i] - 'a']);
137     }
138 }
139
140 static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
141 {
142     return lstrcmpiA(data1, data2);
143 }
144
145 static HANDLE create_mruA(HKEY hKey, DWORD flags, PROC cmp)
146 {
147     mruA.dwFlags = flags;
148     mruA.lpfnCompare = cmp;
149     mruA.hKey = hKey;
150
151     SetLastError(0);
152     return pCreateMRUListA(&mruA);
153 }
154
155 static void test_MRUListA(void)
156 {
157     const char *checks[LIST_SIZE+1];
158     HANDLE hMRU;
159     HKEY hKey;
160     INT iRet;
161
162     pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
163     pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
164     pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
165     if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA)
166         return;
167
168     if (0)
169     {
170     /* Create (NULL) - crashes native */
171     hMRU = pCreateMRUListA(NULL);
172     }
173
174     /* Create (size too small) */
175     mruA.cbSize = sizeof(mruA) - 2;
176     hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
177     ok (!hMRU && !GetLastError(),
178         "CreateMRUListA(too small) expected NULL,0 got %p,%d\n",
179         hMRU, GetLastError());
180     mruA.cbSize = sizeof(mruA);
181
182     /* Create (size too big) */
183     mruA.cbSize = sizeof(mruA) + 2;
184     hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
185     ok (!hMRU && !GetLastError(),
186         "CreateMRUListA(too big) expected NULL,0 got %p,%d\n",
187         hMRU, GetLastError());
188     mruA.cbSize = sizeof(mruA);
189
190     /* Create (NULL hKey) */
191     hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
192     ok (!hMRU && !GetLastError(),
193         "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n",
194         hMRU, GetLastError());
195
196     /* Create (NULL name) */
197     mruA.lpszSubKey = NULL;
198     hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
199     ok (!hMRU && !GetLastError(),
200         "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n",
201         hMRU, GetLastError());
202     mruA.lpszSubKey = REG_TEST_SUBKEYA;
203
204     /* Create a string MRU */
205     ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
206        "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
207     if (!hKey)
208         return;
209     hMRU = create_mruA(hKey, MRUF_STRING_LIST, cmp_mru_strA);
210     ok(hMRU && !GetLastError(),
211        "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n",
212        hMRU, GetLastError());
213
214     if (hMRU)
215     {
216         checks[0] = "Test 1";
217         checks[1] = "Test 2";
218         checks[2] = "Test 3";
219         checks[3] = "Test 4";
220
221         /* Add (NULL list) */
222         SetLastError(0);
223         iRet = pAddMRUStringA(NULL, checks[0]);
224         ok(iRet == -1 && !GetLastError(),
225            "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n",
226            iRet, GetLastError());
227
228         /* Add (NULL string) */
229         if (0)
230         {
231         /* Some native versions crash when passed NULL or fail to SetLastError()  */
232         SetLastError(0);
233         iRet = pAddMRUStringA(hMRU, NULL);
234         ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
235            "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n",
236            iRet, GetLastError());
237         }
238
239         /* Add 3 strings. Check the registry is correct after each add */
240         SetLastError(0);
241         iRet = pAddMRUStringA(hMRU, checks[0]);
242         ok(iRet == 0 && !GetLastError(),
243            "AddMRUStringA(1) expected 0,0 got %d,%d\n",
244            iRet, GetLastError());
245         check_reg_entries("a", checks);
246
247         SetLastError(0);
248         iRet = pAddMRUStringA(hMRU, checks[1]);
249         ok(iRet == 1 && !GetLastError(),
250            "AddMRUStringA(2) expected 1,0 got %d,%d\n",
251            iRet, GetLastError());
252         check_reg_entries("ba", checks);
253
254         SetLastError(0);
255         iRet = pAddMRUStringA(hMRU, checks[2]);
256         ok(iRet == 2 && !GetLastError(),
257            "AddMRUStringA(2) expected 2,0 got %d,%d\n",
258            iRet, GetLastError());
259         check_reg_entries("cba", checks);
260
261         /* Add a duplicate of the 2nd string - it should move to the front,
262          * but keep the same index in the registry.
263          */
264         SetLastError(0);
265         iRet = pAddMRUStringA(hMRU, checks[1]);
266         ok(iRet == 1 && !GetLastError(),
267            "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n",
268            iRet, GetLastError());
269         check_reg_entries("bca", checks);
270
271         /* Add a new string - replaces the oldest string + moves to the front */
272         SetLastError(0);
273         iRet = pAddMRUStringA(hMRU, checks[3]);
274         ok(iRet == 0 && !GetLastError(),
275            "AddMRUStringA(add new) expected 0,0 got %d,%d\n",
276            iRet, GetLastError());
277         checks[0] = checks[3];
278         check_reg_entries("abc", checks);
279
280         /* Finished with this MRU */
281         pFreeMRUList(hMRU);
282     }
283
284     /* Free (NULL list) - Doesn't crash */
285     pFreeMRUList(NULL);
286 }
287
288 START_TEST(mru)
289 {
290     hComctl32 = GetModuleHandleA("comctl32.dll");
291     if (!hComctl32)
292         return;
293
294     delete_reg_entries();
295     if (!create_reg_entries())
296         return;
297
298     test_MRUListA();
299
300     delete_reg_entries();
301 }