Fixes for -Wmissing-declaration and -Wwrite-string warnings.
[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(const 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(const 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, const 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 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 not 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 || retval == ERROR_INVALID_TARGET_HANDLE,
195        "Can't rename many files, retval = %ld\n", retval);
196     ok(file_exists(".\\test1.txt"), "The file is renamed - many files are specified\n");
197
198     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
199     shfo2.fFlags |= FOF_MULTIDESTFILES;
200
201     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
202     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
203     retval = SHFileOperationA(&shfo2); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
204     ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE,
205        "Can't rename many files, retval = %ld\n", retval);
206     ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified\n");
207
208     set_curr_dir_path(from, "test1.txt\0");
209     set_curr_dir_path(to, "test6.txt\0");
210     retval = SHFileOperationA(&shfo);
211     ok(!retval, "Rename file failed, retval = %ld\n", retval);
212     ok(!file_exists(".\\test1.txt"), "The file is not renamed\n");
213     ok(file_exists(".\\test6.txt"), "The file is not renamed\n");
214
215     set_curr_dir_path(from, "test6.txt\0");
216     set_curr_dir_path(to, "test1.txt\0");
217     retval = SHFileOperationA(&shfo);
218     ok(!retval, "Rename file back failed, retval = %ld\n", retval);
219
220     set_curr_dir_path(from, "test4.txt\0");
221     set_curr_dir_path(to, "test6.txt\0");
222     retval = SHFileOperationA(&shfo);
223     ok(!retval, "Rename dir failed, retval = %ld\n", retval);
224     ok(!file_exists(".\\test4.txt"), "The dir is not renamed\n");
225     ok(file_exists(".\\test6.txt"), "The dir is not renamed\n");
226
227     set_curr_dir_path(from, "test6.txt\0");
228     set_curr_dir_path(to, "test4.txt\0");
229     retval = SHFileOperationA(&shfo);
230     ok(!retval, "Rename dir back failed, retval = %ld\n", retval);
231 }
232
233 /* tests the FO_COPY action */
234 void test_copy(void)
235 {
236     SHFILEOPSTRUCTA shfo, shfo2;
237     CHAR from[MAX_PATH];
238     CHAR to[MAX_PATH];
239     FILEOP_FLAGS tmp_flags;
240     DWORD retval;
241
242     shfo.hwnd = NULL;
243     shfo.wFunc = FO_COPY;
244     shfo.pFrom = from;
245     shfo.pTo = to;
246     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
247     shfo.hNameMappings = NULL;
248     shfo.lpszProgressTitle = NULL;
249
250     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
251     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
252     ok(SHFileOperationA(&shfo), "Can't copy many files\n");
253     ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
254        "specified as a target\n");
255
256     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
257     shfo2.fFlags |= FOF_MULTIDESTFILES;
258
259     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
260     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
261     ok(!SHFileOperationA(&shfo2), "Can't copy many files\n");
262     ok(file_exists(".\\test6.txt"), "The file is copied - many files are "
263        "specified as a target\n");
264     DeleteFileA(".\\test6.txt");
265     DeleteFileA(".\\test7.txt");
266     RemoveDirectoryA(".\\test8.txt");
267
268     /* number of sources do not correspond to number of targets */
269     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
270     set_curr_dir_path(to, "test6.txt\0test7.txt\0");
271     ok(SHFileOperationA(&shfo2), "Can't copy many files\n");
272     ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
273        "specified as a target\n");
274
275     set_curr_dir_path(from, "test1.txt\0");
276     set_curr_dir_path(to, "test4.txt\0");
277     ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are copied recursively\n");
278     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is copied\n");
279
280     set_curr_dir_path(from, "test?.txt\0");
281     set_curr_dir_path(to, "testdir2\0");
282     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
283     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
284     ok(!SHFileOperationA(&shfo), "Files and directories are copied to directory\n");
285     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
286     ok(file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
287     ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
288     clean_after_shfo_tests();
289
290     init_shfo_tests();
291     shfo.fFlags |= FOF_FILESONLY;
292     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
293     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
294     ok(!SHFileOperationA(&shfo), "Files are copied to other directory\n");
295     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
296     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
297     clean_after_shfo_tests();
298
299     init_shfo_tests();
300     set_curr_dir_path(from, "test1.txt\0test2.txt\0");
301     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
302     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
303     ok(!SHFileOperationA(&shfo), "Files are copied to other directory \n");
304     ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
305     ok(file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
306     clean_after_shfo_tests();
307
308     /* Copying multiple files with one not existing as source, fails the
309        entire operation in Win98/ME/2K/XP, but not in 95/NT */
310     init_shfo_tests();
311     tmp_flags = shfo.fFlags;
312     set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
313     ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
314     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
315     retval = SHFileOperationA(&shfo);
316     if (!retval)
317       /* Win 95/NT returns success but copies only the files up to the nonexistent source */
318       ok(file_exists(".\\testdir2\\test1.txt"), "The file is not copied\n");
319     else
320     {
321       /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */
322       ok(retval == 1026, "Files are copied to other directory\n");
323       ok(!file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
324     }
325     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
326     shfo.fFlags = tmp_flags;
327 }
328
329 /* tests the FO_MOVE action */
330 void test_move(void)
331 {
332     SHFILEOPSTRUCTA shfo, shfo2;
333     CHAR from[MAX_PATH];
334     CHAR to[MAX_PATH];
335
336     shfo.hwnd = NULL;
337     shfo.wFunc = FO_MOVE;
338     shfo.pFrom = from;
339     shfo.pTo = to;
340     shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
341     shfo.hNameMappings = NULL;
342     shfo.lpszProgressTitle = NULL;
343
344     set_curr_dir_path(from, "test1.txt\0");
345     set_curr_dir_path(to, "test4.txt\0");
346     ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are moved recursively\n");
347     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
348
349     set_curr_dir_path(from, "test?.txt\0");
350     set_curr_dir_path(to, "testdir2\0");
351     ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not moved yet\n");
352     ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not moved yet\n");
353     ok(!SHFileOperationA(&shfo), "Files and directories are moved to directory\n");
354     ok(file_exists(".\\testdir2\\test2.txt"), "The file is moved\n");
355     ok(file_exists(".\\testdir2\\test4.txt"), "The directory is moved\n");
356     ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
357
358     clean_after_shfo_tests();
359     init_shfo_tests();
360
361     memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
362     shfo2.fFlags |= FOF_MULTIDESTFILES;
363
364     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
365     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
366     ok(!SHFileOperationA(&shfo2), "Move many files\n");
367     ok(file_exists(".\\test6.txt"), "The file is moved - many files are "
368        "specified as a target\n");
369     DeleteFileA(".\\test6.txt");
370     DeleteFileA(".\\test7.txt");
371     RemoveDirectoryA(".\\test8.txt");
372
373     init_shfo_tests();
374
375     /* number of sources do not correspond to number of targets */
376     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
377     set_curr_dir_path(to, "test6.txt\0test7.txt\0");
378     ok(SHFileOperationA(&shfo2), "Can't move many files\n");
379     ok(!file_exists(".\\test6.txt"), "The file is not moved - many files are "
380        "specified as a target\n");
381
382     init_shfo_tests();
383
384     set_curr_dir_path(from, "test3.txt\0");
385     set_curr_dir_path(to, "test4.txt\\test1.txt\0");
386     ok(!SHFileOperationA(&shfo), "File is moved moving to other directory\n");
387     ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
388
389     set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
390     set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
391     ok(SHFileOperationA(&shfo), "Cannot move many files\n");
392     ok(file_exists(".\\test1.txt"), "The file is not moved. Many files are specified\n");
393     ok(file_exists(".\\test4.txt"), "The directory is not moved. Many files are specified\n");
394
395     set_curr_dir_path(from, "test1.txt\0");
396     set_curr_dir_path(to, "test6.txt\0");
397     ok(!SHFileOperationA(&shfo), "Move file\n");
398     ok(!file_exists(".\\test1.txt"), "The file is moved\n");
399     ok(file_exists(".\\test6.txt"), "The file is moved\n");
400     set_curr_dir_path(from, "test6.txt\0");
401     set_curr_dir_path(to, "test1.txt\0");
402     ok(!SHFileOperationA(&shfo), "Move file back\n");
403
404     set_curr_dir_path(from, "test4.txt\0");
405     set_curr_dir_path(to, "test6.txt\0");
406     ok(!SHFileOperationA(&shfo), "Move dir\n");
407     ok(!file_exists(".\\test4.txt"), "The dir is moved\n");
408     ok(file_exists(".\\test6.txt"), "The dir is moved\n");
409     set_curr_dir_path(from, "test6.txt\0");
410     set_curr_dir_path(to, "test4.txt\0");
411     ok(!SHFileOperationA(&shfo), "Move dir back\n");
412 }
413
414 void test_sh_create_dir()
415 {
416     CHAR path[MAX_PATH];
417     int ret;
418
419     if(!pSHCreateDirectoryExA)
420     {
421         trace("skipping SHCreateDirectoryExA tests\n");
422         return;
423     }
424
425     set_curr_dir_path(path, "testdir2\\test4.txt\0");
426     ret = pSHCreateDirectoryExA(NULL, path, NULL);
427     ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
428     ok(file_exists(".\\testdir2"), "The first directory is not created\n");
429     ok(file_exists(".\\testdir2\\test4.txt"), "The second directory is not created\n");
430
431     ret = pSHCreateDirectoryExA(NULL, path, NULL);
432     ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
433 }
434
435 START_TEST(shlfileop)
436 {
437     InitFunctionPointers();
438
439     clean_after_shfo_tests();
440
441     init_shfo_tests();
442     test_delete();
443     clean_after_shfo_tests();
444
445     init_shfo_tests();
446     test_rename();
447     clean_after_shfo_tests();
448
449     init_shfo_tests();
450     test_copy();
451     clean_after_shfo_tests();
452
453     init_shfo_tests();
454     test_move();
455     clean_after_shfo_tests();
456
457     test_sh_create_dir();
458     clean_after_shfo_tests();
459 }