Prevent crash when no URL is specified.
[wine] / dlls / shell32 / tests / shlfileop.c
1 /*
2  * Unit test of the SHFileOperation function.
3  *
4  * Copyright 2002 Andriy Palamarchuk
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 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define WINE_NOWINSOCK
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wtypes.h"
28 #include "shellapi.h"
29 #include "shlobj.h"
30
31 #include "wine/test.h"
32
33 CHAR CURR_DIR[MAX_PATH];
34
35 static HMODULE hshell32;
36 static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES);
37
38 static void InitFunctionPointers(void)
39 {
40     hshell32 = GetModuleHandleA("shell32.dll");
41
42     if(hshell32)
43         pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
44 }
45
46 /* creates a file with the specified name for tests */
47 void createTestFile(CHAR *name)
48 {
49     HANDLE file;
50     DWORD written;
51
52     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
53     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
54     WriteFile(file, name, strlen(name), &written, NULL);
55     WriteFile(file, "\n", strlen("\n"), &written, NULL);
56     CloseHandle(file);
57 }
58
59 BOOL file_exists(CHAR *name)
60 {
61     return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
62 }
63
64 /* initializes the tests */
65 void init_shfo_tests(void)
66 {
67     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
68     createTestFile(".\\test1.txt");
69     createTestFile(".\\test2.txt");
70     createTestFile(".\\test3.txt");
71     CreateDirectoryA(".\\test4.txt", NULL);
72     CreateDirectoryA(".\\testdir2", NULL);
73 }
74
75 /* cleans after tests */
76 void clean_after_shfo_tests(void)
77 {
78     DeleteFileA(".\\test1.txt");
79     DeleteFileA(".\\test2.txt");
80     DeleteFileA(".\\test3.txt");
81     DeleteFileA(".\\test4.txt\\test1.txt");
82     DeleteFileA(".\\test4.txt\\test2.txt");
83     DeleteFileA(".\\test4.txt\\test3.txt");
84     RemoveDirectoryA(".\\test4.txt");
85     DeleteFileA(".\\testdir2\\test1.txt");
86     DeleteFileA(".\\testdir2\\test2.txt");
87     DeleteFileA(".\\testdir2\\test3.txt");
88     DeleteFileA(".\\testdir2\\test4.txt\\test1.txt");
89     RemoveDirectoryA(".\\testdir2\\test4.txt");
90     RemoveDirectoryA(".\\testdir2");
91 }
92
93 /*
94  puts into the specified buffer file names with current directory.
95  files - string with file names, separated by null characters. Ends on a double
96  null characters
97 */
98 void set_curr_dir_path(CHAR *buf, CHAR* files)
99 {
100     buf[0] = 0;
101     while (files[0])
102     {
103         strcpy(buf, CURR_DIR);
104         buf += strlen(buf);
105         buf[0] = '\\';
106         buf++;
107         strcpy(buf, files);
108         buf += strlen(buf) + 1;
109         files += strlen(files) + 1;
110     }
111     buf[0] = 0;
112 }
113
114
115 /* tests the FO_DELETE action */
116 void test_delete(void)
117 {
118     SHFILEOPSTRUCTA shfo;
119     DWORD ret;
120     CHAR buf[MAX_PATH];
121
122     sprintf(buf, "%s\\%s", CURR_DIR, "test?.txt");
123     buf[strlen(buf) + 1] = '\0';
124
125     shfo.hwnd = NULL;
126     shfo.wFunc = FO_DELETE;
127     shfo.pFrom = buf;
128     shfo.pTo = "\0";
129     shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT;
130     shfo.hNameMappings = NULL;
131     shfo.lpszProgressTitle = NULL;
132
133     ok(!SHFileOperationA(&shfo), "Deletion was successful\n");
134     ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
135     ok(!file_exists(".\\test1.txt"), "File should be removed\n");
136
137     ret = SHFileOperationA(&shfo);
138     ok(!ret, "Directory exists, but is not removed, ret=%ld\n", ret);
139     ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
140
141     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
142
143     ok(!SHFileOperationA(&shfo), "Directory removed\n");
144     ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
145
146     ret = SHFileOperationA(&shfo);
147     ok(!ret, "The requested file does not exist, ret=%ld\n", ret);
148
149     init_shfo_tests();
150     sprintf(buf, "%s\\%s", CURR_DIR, "test4.txt");
151     buf[strlen(buf) + 1] = '\0';
152     ok(MoveFileA(".\\test1.txt", ".\\test4.txt\\test1.txt"), "Fill the subdirectory\n");
153     ok(!SHFileOperationA(&shfo), "Directory removed\n");
154     ok(!file_exists(".\\test4.txt"), "Directory is removed\n");
155
156     init_shfo_tests();
157     shfo.pFrom = ".\\test1.txt\0.\\test4.txt\0";
158     ok(!SHFileOperationA(&shfo), "Directory and a file removed\n");
159     ok(!file_exists(".\\test1.txt"), "The file should be removed\n");
160     ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
161     ok(file_exists(".\\test2.txt"), "This file should not be removed\n");
162 }
163
164 /* tests the FO_RENAME action */
165 void test_rename()
166 {
167     SHFILEOPSTRUCTA shfo, shfo2;
168     CHAR from[MAX_PATH];
169     CHAR to[MAX_PATH];
170     DWORD retval;
171
172     shfo.hwnd = NULL;
173     shfo.wFunc = FO_RENAME;
174     shfo.pFrom = from;
175     shfo.pTo = to;
176     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
177     shfo.hNameMappings = NULL;
178     shfo.lpszProgressTitle = NULL;
179
180     set_curr_dir_path(from, "test1.txt\0");
181     set_curr_dir_path(to, "test4.txt\0");
182     ok(SHFileOperationA(&shfo), "File is not renamed moving to other directory "
183        "when specifying directory name only\n");
184     ok(file_exists(".\\test1.txt"), "The file is not removed\n");
185
186     set_curr_dir_path(from, "test3.txt\0");
187     set_curr_dir_path(to, "test4.txt\\test1.txt\0");
188     ok(!SHFileOperationA(&shfo), "File is renamed moving to other directory\n");
189     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is renamed\n");
190
191     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
192     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
193     retval = SHFileOperationA(&shfo); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
194     ok(!retval || retval == ERROR_GEN_FAILURE, "Can't rename many files, retval = %lx\n", retval);
195     ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified\n");
196
197     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
198     shfo2.fFlags |= FOF_MULTIDESTFILES;
199
200     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
201     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
202     retval = SHFileOperationA(&shfo2); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
203     ok(!retval || retval == ERROR_GEN_FAILURE, "Can't rename many files, retval = %lx\n", retval);
204     ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified\n");
205
206     set_curr_dir_path(from, "test1.txt\0");
207     set_curr_dir_path(to, "test6.txt\0");
208     ok(!SHFileOperationA(&shfo), "Rename file\n");
209     ok(!file_exists(".\\test1.txt"), "The file is renamed\n");
210     ok(file_exists(".\\test6.txt"), "The file is renamed\n");
211     set_curr_dir_path(from, "test6.txt\0");
212     set_curr_dir_path(to, "test1.txt\0");
213     ok(!SHFileOperationA(&shfo), "Rename file back\n");
214
215     set_curr_dir_path(from, "test4.txt\0");
216     set_curr_dir_path(to, "test6.txt\0");
217     ok(!SHFileOperationA(&shfo), "Rename dir\n");
218     ok(!file_exists(".\\test4.txt"), "The dir is renamed\n");
219     ok(file_exists(".\\test6.txt"), "The dir is renamed\n");
220     set_curr_dir_path(from, "test6.txt\0");
221     set_curr_dir_path(to, "test4.txt\0");
222     ok(!SHFileOperationA(&shfo), "Rename dir back\n");
223 }
224
225 /* tests the FO_COPY action */
226 void test_copy(void)
227 {
228     SHFILEOPSTRUCTA shfo, shfo2;
229     CHAR from[MAX_PATH];
230     CHAR to[MAX_PATH];
231     FILEOP_FLAGS tmp_flags;
232     DWORD retval;
233
234     shfo.hwnd = NULL;
235     shfo.wFunc = FO_COPY;
236     shfo.pFrom = from;
237     shfo.pTo = to;
238     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
239     shfo.hNameMappings = NULL;
240     shfo.lpszProgressTitle = NULL;
241
242     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
243     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
244     ok(SHFileOperationA(&shfo), "Can't copy many files\n");
245     ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
246        "specified as a target\n");
247
248     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
249     shfo2.fFlags |= FOF_MULTIDESTFILES;
250
251     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
252     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
253     ok(!SHFileOperationA(&shfo2), "Can't copy many files\n");
254     ok(file_exists(".\\test6.txt"), "The file is copied - many files are "
255        "specified as a target\n");
256     DeleteFileA(".\\test6.txt");
257     DeleteFileA(".\\test7.txt");
258     RemoveDirectoryA(".\\test8.txt");
259
260     /* number of sources do not correspond to number of targets */
261     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
262     set_curr_dir_path(to, "test6.txt\0test7.txt\0");
263     ok(SHFileOperationA(&shfo2), "Can't copy many files\n");
264     ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
265        "specified as a target\n");
266
267     set_curr_dir_path(from, "test1.txt\0");
268     set_curr_dir_path(to, "test4.txt\0");
269     ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are copied recursively\n");
270     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is copied\n");
271
272     set_curr_dir_path(from, "test?.txt\0");
273     set_curr_dir_path(to, "testdir2\0");
274     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
275     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
276     ok(!SHFileOperationA(&shfo), "Files and directories are copied to directory\n");
277     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
278     ok(file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
279     ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
280     clean_after_shfo_tests();
281
282     init_shfo_tests();
283     shfo.fFlags |= FOF_FILESONLY;
284     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
285     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
286     ok(!SHFileOperationA(&shfo), "Files are copied to other directory\n");
287     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
288     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
289     clean_after_shfo_tests();
290
291     init_shfo_tests();
292     set_curr_dir_path(from, "test1.txt\0test2.txt\0");
293     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
294     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
295     ok(!SHFileOperationA(&shfo), "Files are copied to other directory \n");
296     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
297     ok(file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
298     clean_after_shfo_tests();
299
300     /* Copying multiple files with one not existing as source, fails the
301        entire operation in Win98/ME/2K/XP, but not in 95/NT */
302     init_shfo_tests();
303     tmp_flags = shfo.fFlags;
304     set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
305     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
306     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
307     retval = SHFileOperationA(&shfo);
308     if (!retval)
309       /* Win 95/NT returns success but copies only the files up to the nonexistent source */
310       ok(file_exists(".\\testdir2\\test1.txt"), "The file is not copied\n");
311     else
312     {
313       /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */
314       ok(retval == 1026, "Files are copied to other directory\n");
315       ok(!file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
316     }
317     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
318     shfo.fFlags = tmp_flags;
319 }
320
321 /* tests the FO_MOVE action */
322 void test_move(void)
323 {
324     SHFILEOPSTRUCTA shfo, shfo2;
325     CHAR from[MAX_PATH];
326     CHAR to[MAX_PATH];
327
328     shfo.hwnd = NULL;
329     shfo.wFunc = FO_MOVE;
330     shfo.pFrom = from;
331     shfo.pTo = to;
332     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
333     shfo.hNameMappings = NULL;
334     shfo.lpszProgressTitle = NULL;
335
336     set_curr_dir_path(from, "test1.txt\0");
337     set_curr_dir_path(to, "test4.txt\0");
338     ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are moved recursively\n");
339     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
340
341     set_curr_dir_path(from, "test?.txt\0");
342     set_curr_dir_path(to, "testdir2\0");
343     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not moved yet\n");
344     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not moved yet\n");
345     ok(!SHFileOperationA(&shfo), "Files and directories are moved to directory\n");
346     ok(file_exists(".\\testdir2\\test2.txt"), "The file is moved\n");
347     ok(file_exists(".\\testdir2\\test4.txt"), "The directory is moved\n");
348     ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
349
350     clean_after_shfo_tests();
351     init_shfo_tests();
352
353     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
354     shfo2.fFlags |= FOF_MULTIDESTFILES;
355
356     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
357     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
358     ok(!SHFileOperationA(&shfo2), "Move many files\n");
359     ok(file_exists(".\\test6.txt"), "The file is moved - many files are "
360        "specified as a target\n");
361     DeleteFileA(".\\test6.txt");
362     DeleteFileA(".\\test7.txt");
363     RemoveDirectoryA(".\\test8.txt");
364
365     init_shfo_tests();
366
367     /* number of sources do not correspond to number of targets */
368     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
369     set_curr_dir_path(to, "test6.txt\0test7.txt\0");
370     ok(SHFileOperationA(&shfo2), "Can't move many files\n");
371     ok(!file_exists(".\\test6.txt"), "The file is not moved - many files are "
372        "specified as a target\n");
373
374     init_shfo_tests();
375
376     set_curr_dir_path(from, "test3.txt\0");
377     set_curr_dir_path(to, "test4.txt\\test1.txt\0");
378     ok(!SHFileOperationA(&shfo), "File is moved moving to other directory\n");
379     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
380
381     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
382     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
383     ok(SHFileOperationA(&shfo), "Can not move many files\n");
384     ok(file_exists(".\\test1.txt"), "The file is not moved. Many files are specified\n");
385     ok(file_exists(".\\test4.txt"), "The directory is not moved. Many files are specified\n");
386
387     set_curr_dir_path(from, "test1.txt\0");
388     set_curr_dir_path(to, "test6.txt\0");
389     ok(!SHFileOperationA(&shfo), "Move file\n");
390     ok(!file_exists(".\\test1.txt"), "The file is moved\n");
391     ok(file_exists(".\\test6.txt"), "The file is moved\n");
392     set_curr_dir_path(from, "test6.txt\0");
393     set_curr_dir_path(to, "test1.txt\0");
394     ok(!SHFileOperationA(&shfo), "Move file back\n");
395
396     set_curr_dir_path(from, "test4.txt\0");
397     set_curr_dir_path(to, "test6.txt\0");
398     ok(!SHFileOperationA(&shfo), "Move dir\n");
399     ok(!file_exists(".\\test4.txt"), "The dir is moved\n");
400     ok(file_exists(".\\test6.txt"), "The dir is moved\n");
401     set_curr_dir_path(from, "test6.txt\0");
402     set_curr_dir_path(to, "test4.txt\0");
403     ok(!SHFileOperationA(&shfo), "Move dir back\n");
404 }
405
406 void test_sh_create_dir()
407 {
408     CHAR path[MAX_PATH];
409     int ret;
410
411     if(!pSHCreateDirectoryExA)
412     {
413         trace("skipping SHCreateDirectoryExA tests\n");
414         return;
415     }
416
417     set_curr_dir_path(path, "testdir2\\test4.txt\0");
418     ret = pSHCreateDirectoryExA(NULL, path, NULL);
419     ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
420     ok(file_exists(".\\testdir2"), "The first directory is not created\n");
421     ok(file_exists(".\\testdir2\\test4.txt"), "The second directory is not created\n");
422
423     ret = pSHCreateDirectoryExA(NULL, path, NULL);
424     ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
425 }
426
427 START_TEST(shlfileop)
428 {
429     InitFunctionPointers();
430
431     clean_after_shfo_tests();
432
433     init_shfo_tests();
434     test_delete();
435     clean_after_shfo_tests();
436
437     init_shfo_tests();
438     test_rename();
439     clean_after_shfo_tests();
440
441     init_shfo_tests();
442     test_copy();
443     clean_after_shfo_tests();
444
445     init_shfo_tests();
446     test_move();
447     clean_after_shfo_tests();
448
449     test_sh_create_dir();
450     clean_after_shfo_tests();
451 }