wined3d: Rename "NumberOfSwapChains" to "swapchain_count".
[wine] / dlls / setupapi / tests / setupcab.c
1 /*
2  * Unit tests for SetupIterateCabinet
3  *
4  * Copyright 2007 Hans Leidekker
5  * Copyright 2010 Andrew Nguyen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30 #include "wine/test.h"
31
32 static const BYTE comp_cab_zip_multi[] = {
33     0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34     0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
35     0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00,
36     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x74, 0x72, 0x69, 0x73,
37     0x74, 0x72, 0x61, 0x6d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1,
38     0x38, 0xf0, 0x48, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00,
39     0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x73, 0x68, 0x61, 0x6e, 0x64, 0x79,
40     0x00, 0x67, 0x2c, 0x03, 0x85, 0x23, 0x00, 0x20, 0x00, 0x43, 0x4b, 0xcb, 0x49, 0x2c, 0x2d, 0x4a,
41     0xcd, 0x4b, 0x4e, 0xe5, 0xe5, 0x2a, 0xcd, 0x4b, 0xce, 0xcf, 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e,
42     0x4d, 0xe1, 0xe5, 0x2a, 0x2e, 0x49, 0x2d, 0xca, 0x03, 0x8a, 0x02, 0x00
43 };
44
45 static const WCHAR docW[] = {'d','o','c',0};
46
47 static void create_source_fileA(LPSTR filename, const BYTE *data, DWORD size)
48 {
49     HANDLE handle;
50     DWORD written;
51
52     handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
53                          FILE_ATTRIBUTE_NORMAL, NULL);
54     WriteFile(handle, data, size, &written, NULL);
55     CloseHandle(handle);
56 }
57
58 static void create_source_fileW(LPWSTR filename, const BYTE *data, DWORD size)
59 {
60     HANDLE handle;
61     DWORD written;
62
63     handle = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
64                          FILE_ATTRIBUTE_NORMAL, NULL);
65     WriteFile(handle, data, size, &written, NULL);
66     CloseHandle(handle);
67 }
68
69 static UINT CALLBACK dummy_callbackA(PVOID Context, UINT Notification,
70                                      UINT_PTR Param1, UINT_PTR Param2)
71 {
72     ok(0, "Received unexpected notification (%p, %u, %lu, %lu)\n", Context,
73        Notification, Param1, Param2);
74     return 0;
75 }
76
77 static UINT CALLBACK dummy_callbackW(PVOID Context, UINT Notification,
78                                      UINT_PTR Param1, UINT_PTR Param2)
79 {
80     ok(0, "Received unexpected notification (%p, %u, %lu, %lu)\n", Context,
81        Notification, Param1, Param2);
82     return 0;
83 }
84
85 static void test_invalid_parametersA(void)
86 {
87     BOOL ret;
88     char source[MAX_PATH], temp[MAX_PATH];
89     int i;
90
91     const struct
92     {
93         PCSTR CabinetFile;
94         PSP_FILE_CALLBACK MsgHandler;
95         DWORD expected_lasterror;
96         int todo_lasterror;
97     } invalid_parameters[] =
98     {
99         {NULL,                  NULL,            ERROR_INVALID_PARAMETER},
100         {NULL,                  dummy_callbackA, ERROR_INVALID_PARAMETER},
101         {"c:\\nonexistent.cab", NULL,            ERROR_FILE_NOT_FOUND},
102         {"c:\\nonexistent.cab", dummy_callbackA, ERROR_FILE_NOT_FOUND},
103         {source,                NULL,            ERROR_INVALID_DATA, 1},
104         {source,                dummy_callbackA, ERROR_INVALID_DATA, 1},
105     };
106
107     GetTempPathA(sizeof(temp), temp);
108     GetTempFileNameA(temp, "doc", 0, source);
109
110     create_source_fileA(source, NULL, 0);
111
112     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
113     {
114         SetLastError(0xdeadbeef);
115         ret = SetupIterateCabinetA(invalid_parameters[i].CabinetFile, 0,
116                                    invalid_parameters[i].MsgHandler, NULL);
117         ok(!ret, "[%d] Expected SetupIterateCabinetA to return 0, got %d\n", i, ret);
118         if (invalid_parameters[i].todo_lasterror)
119         {
120             todo_wine
121             ok(GetLastError() == invalid_parameters[i].expected_lasterror,
122                "[%d] Expected GetLastError() to return %u, got %u\n",
123                i, invalid_parameters[i].expected_lasterror, GetLastError());
124         }
125         else
126         {
127             ok(GetLastError() == invalid_parameters[i].expected_lasterror,
128                "[%d] Expected GetLastError() to return %u, got %u\n",
129                i, invalid_parameters[i].expected_lasterror, GetLastError());
130         }
131     }
132
133     SetLastError(0xdeadbeef);
134     ret = SetupIterateCabinetA("", 0, NULL, NULL);
135     ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret);
136     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
137        GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x/NT4/Win2k */
138        "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n",
139        GetLastError());
140
141     SetLastError(0xdeadbeef);
142     ret = SetupIterateCabinetA("", 0, dummy_callbackA, NULL);
143     ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret);
144     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
145        GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x/NT4/Win2k */
146        "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n",
147        GetLastError());
148
149     DeleteFileA(source);
150 }
151
152 static void test_invalid_parametersW(void)
153 {
154     static const WCHAR nonexistentW[] = {'c',':','\\','n','o','n','e','x','i','s','t','e','n','t','.','c','a','b',0};
155     static const WCHAR emptyW[] = {0};
156
157     BOOL ret;
158     WCHAR source[MAX_PATH], temp[MAX_PATH];
159     int i;
160
161     const struct
162     {
163         PCWSTR CabinetFile;
164         PSP_FILE_CALLBACK MsgHandler;
165         DWORD expected_lasterror;
166         int todo_lasterror;
167     } invalid_parameters[] =
168     {
169         {nonexistentW, NULL,            ERROR_FILE_NOT_FOUND},
170         {nonexistentW, dummy_callbackW, ERROR_FILE_NOT_FOUND},
171         {source,       NULL,            ERROR_INVALID_DATA, 1},
172         {source,       dummy_callbackW, ERROR_INVALID_DATA, 1},
173     };
174
175     ret = SetupIterateCabinetW(NULL, 0, NULL, NULL);
176     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
177     {
178         win_skip("SetupIterateCabinetW is not available\n");
179         return;
180     }
181
182     GetTempPathW(sizeof(temp)/sizeof(WCHAR), temp);
183     GetTempFileNameW(temp, docW, 0, source);
184
185     create_source_fileW(source, NULL, 0);
186
187     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
188     {
189         SetLastError(0xdeadbeef);
190         ret = SetupIterateCabinetW(invalid_parameters[i].CabinetFile, 0,
191                                    invalid_parameters[i].MsgHandler, NULL);
192         ok(!ret, "[%d] Expected SetupIterateCabinetW to return 0, got %d\n", i, ret);
193         if (invalid_parameters[i].todo_lasterror)
194         {
195             todo_wine
196             ok(GetLastError() == invalid_parameters[i].expected_lasterror,
197                "[%d] Expected GetLastError() to return %u, got %u\n",
198                i, invalid_parameters[i].expected_lasterror, GetLastError());
199         }
200         else
201         {
202             ok(GetLastError() == invalid_parameters[i].expected_lasterror,
203                "[%d] Expected GetLastError() to return %u, got %u\n",
204                i, invalid_parameters[i].expected_lasterror, GetLastError());
205         }
206     }
207
208     SetLastError(0xdeadbeef);
209     ret = SetupIterateCabinetW(NULL, 0, NULL, NULL);
210     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
211     ok(GetLastError() == ERROR_INVALID_PARAMETER ||
212        GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Vista/Win2k8 */
213        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
214        GetLastError());
215
216     SetLastError(0xdeadbeef);
217     ret = SetupIterateCabinetW(NULL, 0, dummy_callbackW, NULL);
218     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
219     ok(GetLastError() == ERROR_INVALID_PARAMETER ||
220        GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Vista/Win2k8 */
221        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
222        GetLastError());
223
224     SetLastError(0xdeadbeef);
225     ret = SetupIterateCabinetW(emptyW, 0, NULL, NULL);
226     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
227     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
228        GetLastError() == ERROR_FILE_NOT_FOUND, /* NT4/Win2k */
229        "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n",
230        GetLastError());
231
232     SetLastError(0xdeadbeef);
233     ret = SetupIterateCabinetW(emptyW, 0, dummy_callbackW, NULL);
234     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
235     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
236        GetLastError() == ERROR_FILE_NOT_FOUND, /* NT4/Win2k */
237        "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n",
238        GetLastError());
239
240     DeleteFileW(source);
241 }
242
243 static UINT CALLBACK crash_callbackA(PVOID Context, UINT Notification,
244                                      UINT_PTR Param1, UINT_PTR Param2)
245 {
246     *(volatile char*)0 = 2;
247     return 0;
248 }
249
250 static UINT CALLBACK crash_callbackW(PVOID Context, UINT Notification,
251                                      UINT_PTR Param1, UINT_PTR Param2)
252 {
253     *(volatile char*)0 = 2;
254     return 0;
255 }
256
257 static void test_invalid_callbackA(void)
258 {
259     BOOL ret;
260     char source[MAX_PATH], temp[MAX_PATH];
261
262     GetTempPathA(sizeof(temp), temp);
263     GetTempFileNameA(temp, "doc", 0, source);
264
265     create_source_fileA(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi));
266
267     SetLastError(0xdeadbeef);
268     ret = SetupIterateCabinetA(source, 0, NULL, NULL);
269     ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret);
270     ok(GetLastError() == ERROR_INVALID_DATA,
271        "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n",
272        GetLastError());
273
274     SetLastError(0xdeadbeef);
275     ret = SetupIterateCabinetA(source, 0, crash_callbackA, NULL);
276     ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret);
277     ok(GetLastError() == ERROR_INVALID_DATA,
278        "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n",
279        GetLastError());
280
281     DeleteFileA(source);
282 }
283
284 static void test_invalid_callbackW(void)
285 {
286     BOOL ret;
287     WCHAR source[MAX_PATH], temp[MAX_PATH];
288
289     ret = SetupIterateCabinetW(NULL, 0, NULL, NULL);
290     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
291     {
292         win_skip("SetupIterateCabinetW is not available\n");
293         return;
294     }
295
296     GetTempPathW(sizeof(temp)/sizeof(WCHAR), temp);
297     GetTempFileNameW(temp, docW, 0, source);
298
299     create_source_fileW(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi));
300
301     SetLastError(0xdeadbeef);
302     ret = SetupIterateCabinetW(source, 0, NULL, NULL);
303     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
304     ok(GetLastError() == ERROR_INVALID_DATA,
305        "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n",
306        GetLastError());
307
308     SetLastError(0xdeadbeef);
309     ret = SetupIterateCabinetW(source, 0, crash_callbackW, NULL);
310     ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret);
311     ok(GetLastError() == ERROR_INVALID_DATA,
312        "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n",
313        GetLastError());
314
315     DeleteFileW(source);
316 }
317
318 static const char *expected_files[] = {"tristram", "wine", "shandy"};
319
320 static UINT CALLBACK simple_callbackA(PVOID Context, UINT Notification,
321                                       UINT_PTR Param1, UINT_PTR Param2)
322 {
323     static int index;
324     int *file_count = Context;
325
326     switch (Notification)
327     {
328     case SPFILENOTIFY_CABINETINFO:
329         index = 0;
330         return NO_ERROR;
331     case SPFILENOTIFY_FILEINCABINET:
332     {
333         FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)Param1;
334
335         (*file_count)++;
336
337         if (index < sizeof(expected_files)/sizeof(char *))
338         {
339             ok(!strcmp(expected_files[index], info->NameInCabinet),
340                "[%d] Expected file \"%s\", got \"%s\"\n",
341                index, expected_files[index], info->NameInCabinet);
342             index++;
343             return FILEOP_SKIP;
344         }
345         else
346         {
347             ok(0, "Unexpectedly enumerated more than number of files in cabinet, index = %d\n", index);
348             return FILEOP_ABORT;
349         }
350     }
351     default:
352         return NO_ERROR;
353     }
354 }
355
356 static void test_simple_enumerationA(void)
357 {
358     BOOL ret;
359     char source[MAX_PATH], temp[MAX_PATH];
360     int enum_count = 0;
361
362     GetTempPathA(sizeof(temp), temp);
363     GetTempFileNameA(temp, "doc", 0, source);
364
365     create_source_fileA(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi));
366
367     ret = SetupIterateCabinetA(source, 0, simple_callbackA, &enum_count);
368     ok(ret == 1, "Expected SetupIterateCabinetA to return 1, got %d\n", ret);
369     ok(enum_count == sizeof(expected_files)/sizeof(char *),
370        "Unexpectedly enumerated %d files\n", enum_count);
371
372     DeleteFileA(source);
373 }
374
375 static const WCHAR tristramW[] = {'t','r','i','s','t','r','a','m',0};
376 static const WCHAR wineW[] = {'w','i','n','e',0};
377 static const WCHAR shandyW[] = {'s','h','a','n','d','y',0};
378 static const WCHAR *expected_filesW[] = {tristramW, wineW, shandyW};
379
380 static UINT CALLBACK simple_callbackW(PVOID Context, UINT Notification,
381                                       UINT_PTR Param1, UINT_PTR Param2)
382 {
383     static int index;
384     int *file_count = Context;
385
386     switch (Notification)
387     {
388     case SPFILENOTIFY_CABINETINFO:
389         index = 0;
390         return NO_ERROR;
391     case SPFILENOTIFY_FILEINCABINET:
392     {
393         FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)Param1;
394
395         (*file_count)++;
396
397         if (index < sizeof(expected_filesW)/sizeof(WCHAR *))
398         {
399             ok(!lstrcmpW(expected_filesW[index], info->NameInCabinet),
400                "[%d] Expected file %s, got %s\n",
401                index, wine_dbgstr_w(expected_filesW[index]), wine_dbgstr_w(info->NameInCabinet));
402             index++;
403             return FILEOP_SKIP;
404         }
405         else
406         {
407             ok(0, "Unexpectedly enumerated more than number of files in cabinet, index = %d\n", index);
408             return FILEOP_ABORT;
409         }
410     }
411     default:
412         return NO_ERROR;
413     }
414 }
415
416 static void test_simple_enumerationW(void)
417 {
418     BOOL ret;
419     WCHAR source[MAX_PATH], temp[MAX_PATH];
420     int enum_count = 0;
421
422     ret = SetupIterateCabinetW(NULL, 0, NULL, NULL);
423     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
424     {
425         win_skip("SetupIterateCabinetW is not available\n");
426         return;
427     }
428
429     GetTempPathW(sizeof(temp)/sizeof(WCHAR), temp);
430     GetTempFileNameW(temp, docW, 0, source);
431
432     create_source_fileW(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi));
433
434     ret = SetupIterateCabinetW(source, 0, simple_callbackW, &enum_count);
435     ok(ret == 1, "Expected SetupIterateCabinetW to return 1, got %d\n", ret);
436     ok(enum_count == sizeof(expected_files)/sizeof(WCHAR *),
437        "Unexpectedly enumerated %d files\n", enum_count);
438
439     DeleteFileW(source);
440 }
441
442 START_TEST(setupcab)
443 {
444     test_invalid_parametersA();
445     test_invalid_parametersW();
446
447     /* Tests crash on NT4/Win9x/Win2k and Wine. */
448     if (0)
449     {
450         test_invalid_callbackA();
451         test_invalid_callbackW();
452     }
453
454     test_simple_enumerationA();
455     test_simple_enumerationW();
456 }