user32/tests: Fix a test failure on Win95.
[wine] / dlls / qmgr / tests / job.c
1 /*
2  * Unit test suite for Background Copy Job Interface
3  *
4  * Copyright 2007 Google (Roy Shea)
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
21 #include <stdio.h>
22
23 #define COBJMACROS
24
25 #include "wine/test.h"
26 #include "bits.h"
27 #include "initguid.h"
28
29 /* Globals used by many tests */
30 static const WCHAR test_displayName[] = {'T', 'e', 's', 't', 0};
31 static const WCHAR test_remoteNameA[] = {'r','e','m','o','t','e','A', 0};
32 static const WCHAR test_remoteNameB[] = {'r','e','m','o','t','e','B', 0};
33 static const WCHAR test_localNameA[] = {'l','o','c','a','l','A', 0};
34 static const WCHAR test_localNameB[] = {'l','o','c','a','l','B', 0};
35 static WCHAR *test_currentDir;
36 static WCHAR *test_remotePathA;
37 static WCHAR *test_remotePathB;
38 static WCHAR *test_localPathA;
39 static WCHAR *test_localPathB;
40 static IBackgroundCopyManager *test_manager;
41 static IBackgroundCopyJob *test_job;
42 static GUID test_jobId;
43 static BG_JOB_TYPE test_type;
44
45 static BOOL init_paths(void)
46 {
47     static const WCHAR format[] = {'%','s','\\','%','s', 0};
48     DWORD n;
49
50     n = GetCurrentDirectoryW(0, NULL);
51     if (n == 0)
52     {
53         skip("Couldn't get current directory size\n");
54         return FALSE;
55     }
56
57     test_currentDir = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
58     test_localPathA
59         = HeapAlloc(GetProcessHeap(), 0,
60                     (n + 1 + lstrlenW(test_localNameA)) * sizeof(WCHAR));
61     test_localPathB
62         = HeapAlloc(GetProcessHeap(), 0,
63                     (n + 1 + lstrlenW(test_localNameB)) * sizeof(WCHAR));
64     test_remotePathA
65         = HeapAlloc(GetProcessHeap(), 0,
66                     (n + 1 + lstrlenW(test_remoteNameA)) * sizeof(WCHAR));
67     test_remotePathB
68         = HeapAlloc(GetProcessHeap(), 0,
69                     (n + 1 + lstrlenW(test_remoteNameB)) * sizeof(WCHAR));
70
71     if (!test_currentDir || !test_localPathA || !test_localPathB
72         || !test_remotePathA || !test_remotePathB)
73     {
74         skip("Couldn't allocate memory for full paths\n");
75         return FALSE;
76     }
77
78     if (GetCurrentDirectoryW(n, test_currentDir) != n - 1)
79     {
80         skip("Couldn't get current directory\n");
81         return FALSE;
82     }
83
84     wsprintfW(test_localPathA, format, test_currentDir, test_localNameA);
85     wsprintfW(test_localPathB, format, test_currentDir, test_localNameB);
86     wsprintfW(test_remotePathA, format, test_currentDir, test_remoteNameA);
87     wsprintfW(test_remotePathB, format, test_currentDir, test_remoteNameB);
88
89     return TRUE;
90 }
91
92 /* Generic test setup */
93 static BOOL setup(void)
94 {
95     HRESULT hres;
96
97     test_manager = NULL;
98     test_job = NULL;
99     memset(&test_jobId, 0, sizeof test_jobId);
100     test_type = BG_JOB_TYPE_DOWNLOAD;
101
102     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL,
103                             CLSCTX_LOCAL_SERVER,
104                             &IID_IBackgroundCopyManager,
105                             (void **) &test_manager);
106     if(hres != S_OK)
107         return FALSE;
108
109     hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName,
110                                             test_type, &test_jobId, &test_job);
111     if(hres != S_OK)
112     {
113         IBackgroundCopyManager_Release(test_manager);
114         return FALSE;
115     }
116
117     return TRUE;
118 }
119
120 /* Generic test cleanup */
121 static void teardown(void)
122 {
123     IBackgroundCopyJob_Release(test_job);
124     IBackgroundCopyManager_Release(test_manager);
125 }
126
127 /* FIXME: Remove when Wine has implemented this */
128 DEFINE_GUID(CLSID_BackgroundCopyManager2_0, 0x6d18ad12, 0xbde3, 0x4393, 0xb3,0x11, 0x09,0x9c,0x34,0x6e,0x6d,0xf9);
129
130 static BOOL check_bits20(void)
131 {
132     HRESULT hres;
133     IBackgroundCopyManager *manager;
134     BOOL ret = TRUE;
135
136     hres = CoCreateInstance(&CLSID_BackgroundCopyManager2_0, NULL,
137                             CLSCTX_LOCAL_SERVER,
138                             &IID_IBackgroundCopyManager,
139                             (void **) &manager);
140
141     if (hres == REGDB_E_CLASSNOTREG)
142     {
143         ret = FALSE;
144
145         /* FIXME: Wine implements 2.0 functionality but doesn't advertise 2.0
146          *
147          * Remove when Wine is fixed
148          */
149         if (setup())
150         {
151             HRESULT hres2;
152
153             hres2 = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
154                                                test_localPathA);
155             if (hres2 == S_OK)
156             {
157                 trace("Running on Wine, claim 2.0 is present\n");
158                 ret = TRUE;
159             }
160             teardown();
161         }
162     }
163
164     if (manager)
165         IBackgroundCopyManager_Release(manager);
166
167     return ret;
168 }
169
170 /* Test that the jobId is properly set */
171 static void test_GetId(void)
172 {
173     HRESULT hres;
174     GUID tmpId;
175
176     hres = IBackgroundCopyJob_GetId(test_job, &tmpId);
177     ok(hres == S_OK, "GetId failed: %08x\n", hres);
178     if(hres != S_OK)
179     {
180         skip("Unable to get ID of test_job.\n");
181         return;
182     }
183     ok(memcmp(&tmpId, &test_jobId, sizeof tmpId) == 0, "Got incorrect GUID\n");
184 }
185
186 /* Test that the type is properly set */
187 static void test_GetType(void)
188 {
189     HRESULT hres;
190     BG_JOB_TYPE type;
191
192     hres = IBackgroundCopyJob_GetType(test_job, &type);
193     ok(hres == S_OK, "GetType failed: %08x\n", hres);
194     if(hres != S_OK)
195     {
196         skip("Unable to get type of test_job.\n");
197         return;
198     }
199     ok(type == test_type, "Got incorrect type\n");
200 }
201
202 /* Test that the display name is properly set */
203 static void test_GetName(void)
204 {
205     HRESULT hres;
206     LPWSTR displayName;
207
208     hres = IBackgroundCopyJob_GetDisplayName(test_job, &displayName);
209     ok(hres == S_OK, "GetName failed: %08x\n", hres);
210     if(hres != S_OK)
211     {
212         skip("Unable to get display name of test_job.\n");
213         return;
214     }
215     ok(lstrcmpW(displayName, test_displayName) == 0, "Got incorrect type\n");
216     CoTaskMemFree(displayName);
217 }
218
219 /* Test adding a file */
220 static void test_AddFile(void)
221 {
222     HRESULT hres;
223
224     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
225                                       test_localPathA);
226     ok(hres == S_OK, "First call to AddFile failed: 0x%08x\n", hres);
227     if (hres != S_OK)
228     {
229         skip("Unable to add first file to job\n");
230         return;
231     }
232
233     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
234                                       test_localPathB);
235     ok(hres == S_OK, "Second call to AddFile failed: 0x%08x\n", hres);
236 }
237
238 /* Test adding a set of files */
239 static void test_AddFileSet(void)
240 {
241     HRESULT hres;
242     BG_FILE_INFO files[2] =
243         {
244             {test_remotePathA, test_localPathA},
245             {test_remotePathB, test_localPathB}
246         };
247     hres = IBackgroundCopyJob_AddFileSet(test_job, 2, files);
248     ok(hres == S_OK, "AddFileSet failed: 0x%08x\n", hres);
249 }
250
251 /* Test creation of a job enumerator */
252 static void test_EnumFiles(void)
253 {
254     HRESULT hres;
255     IEnumBackgroundCopyFiles *enumFiles;
256     ULONG res;
257
258     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
259                                       test_localPathA);
260     if (hres != S_OK)
261     {
262         skip("Unable to add file to job\n");
263         return;
264     }
265
266     hres = IBackgroundCopyJob_EnumFiles(test_job, &enumFiles);
267     ok(hres == S_OK, "EnumFiles failed: 0x%08x\n", hres);
268     if(hres != S_OK)
269     {
270         skip("Unable to create file enumerator.\n");
271         return;
272     }
273
274     res = IEnumBackgroundCopyFiles_Release(enumFiles);
275     ok(res == 0, "Bad ref count on release: %u\n", res);
276 }
277
278 /* Test getting job progress */
279 static void test_GetProgress_preTransfer(void)
280 {
281     HRESULT hres;
282     BG_JOB_PROGRESS progress;
283
284     hres = IBackgroundCopyJob_GetProgress(test_job, &progress);
285     ok(hres == S_OK, "GetProgress failed: 0x%08x\n", hres);
286     if (hres != S_OK)
287     {
288         skip("Unable to get job progress\n");
289         teardown();
290         return;
291     }
292
293     ok(progress.BytesTotal == 0, "Incorrect BytesTotal: %x%08x\n",
294        (DWORD)(progress.BytesTotal >> 32), (DWORD)progress.BytesTotal);
295     ok(progress.BytesTransferred == 0, "Incorrect BytesTransferred: %x%08x\n",
296        (DWORD)(progress.BytesTransferred >> 32), (DWORD)progress.BytesTransferred);
297     ok(progress.FilesTotal == 0, "Incorrect FilesTotal: %u\n", progress.FilesTotal);
298     ok(progress.FilesTransferred == 0, "Incorrect FilesTransferred %u\n", progress.FilesTransferred);
299 }
300
301 /* Test getting job state */
302 static void test_GetState(void)
303 {
304     HRESULT hres;
305     BG_JOB_STATE state;
306
307     state = BG_JOB_STATE_ERROR;
308     hres = IBackgroundCopyJob_GetState(test_job, &state);
309     ok(hres == S_OK, "GetState failed: 0x%08x\n", hres);
310     if (hres != S_OK)
311     {
312         skip("Unable to get job state\n");
313         return;
314     }
315     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
316 }
317
318 /* Test resuming a job */
319 static void test_ResumeEmpty(void)
320 {
321     HRESULT hres;
322     BG_JOB_STATE state;
323
324     hres = IBackgroundCopyJob_Resume(test_job);
325     ok(hres == BG_E_EMPTY, "Resume failed to return BG_E_EMPTY error: 0x%08x\n", hres);
326     if (hres != BG_E_EMPTY)
327     {
328         skip("Failed calling resume job\n");
329         return;
330     }
331
332     state = BG_JOB_STATE_ERROR;
333     hres = IBackgroundCopyJob_GetState(test_job, &state);
334     if (hres != S_OK)
335     {
336         skip("Unable to get job state\n");
337         return;
338     }
339     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
340 }
341
342 static void makeFile(WCHAR *name, const char *contents)
343 {
344     HANDLE file;
345     DWORD w, len = strlen(contents);
346
347     DeleteFileW(name);
348     file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
349                        FILE_ATTRIBUTE_NORMAL, NULL);
350     ok(file != INVALID_HANDLE_VALUE, "CreateFile\n");
351     ok(WriteFile(file, contents, len, &w, NULL), "WriteFile\n");
352     CloseHandle(file);
353 }
354
355 static void compareFiles(WCHAR *n1, WCHAR *n2)
356 {
357     char b1[256];
358     char b2[256];
359     DWORD s1, s2;
360     HANDLE f1, f2;
361
362     f1 = CreateFileW(n1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
363                      FILE_ATTRIBUTE_NORMAL, NULL);
364     ok(f1 != INVALID_HANDLE_VALUE, "CreateFile\n");
365
366     f2 = CreateFileW(n2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
367                      FILE_ATTRIBUTE_NORMAL, NULL);
368     ok(f2 != INVALID_HANDLE_VALUE, "CreateFile\n");
369
370     /* Neither of these files is very big */
371     ok(ReadFile(f1, b1, sizeof b1, &s1, NULL), "ReadFile\n");
372     ok(ReadFile(f2, b2, sizeof b2, &s2, NULL), "ReadFile\n");
373
374     CloseHandle(f1);
375     CloseHandle(f2);
376
377     ok(s1 == s2, "Files differ in length\n");
378     ok(memcmp(b1, b2, s1) == 0, "Files differ in contents\n");
379 }
380
381 /* Test a complete transfer for local files */
382 static void test_CompleteLocal(void)
383 {
384     static const int timeout_sec = 30;
385     HRESULT hres;
386     BG_JOB_STATE state;
387     int i;
388
389     DeleteFileW(test_localPathA);
390     DeleteFileW(test_localPathB);
391     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
392     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
393
394     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
395                                       test_localPathA);
396     if (hres != S_OK)
397     {
398         skip("Unable to add file to job\n");
399         return;
400     }
401
402     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
403                                       test_localPathB);
404     if (hres != S_OK)
405     {
406         skip("Unable to add file to job\n");
407         return;
408     }
409
410     hres = IBackgroundCopyJob_Resume(test_job);
411     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
412
413     for (i = 0; i < timeout_sec; ++i)
414     {
415         hres = IBackgroundCopyJob_GetState(test_job, &state);
416         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
417         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
418            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
419            "Bad state: %d\n", state);
420         if (state == BG_JOB_STATE_TRANSFERRED)
421             break;
422         Sleep(1000);
423     }
424
425     ok(i < timeout_sec, "BITS jobs timed out\n");
426     hres = IBackgroundCopyJob_Complete(test_job);
427     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
428     hres = IBackgroundCopyJob_GetState(test_job, &state);
429     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
430     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
431
432     compareFiles(test_remotePathA, test_localPathA);
433     compareFiles(test_remotePathB, test_localPathB);
434
435     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
436     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
437     DeleteFileW(test_localPathA);
438     DeleteFileW(test_localPathB);
439 }
440
441 /* Test a complete transfer for local files */
442 static void test_CompleteLocalURL(void)
443 {
444     static const WCHAR prot[] = {'f','i','l','e',':','/','/', 0};
445     static const int timeout_sec = 30;
446     WCHAR *urlA, *urlB;
447     HRESULT hres;
448     BG_JOB_STATE state;
449     int i;
450
451     DeleteFileW(test_localPathA);
452     DeleteFileW(test_localPathB);
453     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
454     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
455
456     urlA = HeapAlloc(GetProcessHeap(), 0,
457                      (7 + lstrlenW(test_remotePathA) + 1) * sizeof urlA[0]);
458     urlB = HeapAlloc(GetProcessHeap(), 0,
459                      (7 + lstrlenW(test_remotePathB) + 1) * sizeof urlB[0]);
460     if (!urlA || !urlB)
461     {
462         skip("Unable to allocate memory for URLs\n");
463         HeapFree(GetProcessHeap(), 0, urlA);
464         HeapFree(GetProcessHeap(), 0, urlB);
465         return;
466     }
467
468     lstrcpyW(urlA, prot);
469     lstrcatW(urlA, test_remotePathA);
470     lstrcpyW(urlB, prot);
471     lstrcatW(urlB, test_remotePathB);
472
473     hres = IBackgroundCopyJob_AddFile(test_job, urlA, test_localPathA);
474     if (hres != S_OK)
475     {
476         skip("Unable to add file to job\n");
477         HeapFree(GetProcessHeap(), 0, urlA);
478         HeapFree(GetProcessHeap(), 0, urlB);
479         return;
480     }
481
482     hres = IBackgroundCopyJob_AddFile(test_job, urlB, test_localPathB);
483     if (hres != S_OK)
484     {
485         skip("Unable to add file to job\n");
486         HeapFree(GetProcessHeap(), 0, urlA);
487         HeapFree(GetProcessHeap(), 0, urlB);
488         return;
489     }
490
491     hres = IBackgroundCopyJob_Resume(test_job);
492     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
493
494     for (i = 0; i < timeout_sec; ++i)
495     {
496         hres = IBackgroundCopyJob_GetState(test_job, &state);
497         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
498         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
499            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
500            "Bad state: %d\n", state);
501         if (state == BG_JOB_STATE_TRANSFERRED)
502             break;
503         Sleep(1000);
504     }
505
506     ok(i < timeout_sec, "BITS jobs timed out\n");
507     hres = IBackgroundCopyJob_Complete(test_job);
508     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
509     hres = IBackgroundCopyJob_GetState(test_job, &state);
510     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
511     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
512
513     compareFiles(test_remotePathA, test_localPathA);
514     compareFiles(test_remotePathB, test_localPathB);
515
516     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
517     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
518     DeleteFileW(test_localPathA);
519     DeleteFileW(test_localPathB);
520
521     HeapFree(GetProcessHeap(), 0, urlA);
522     HeapFree(GetProcessHeap(), 0, urlB);
523 }
524
525 typedef void (*test_t)(void);
526
527 START_TEST(job)
528 {
529     static const test_t tests[] = {
530         test_GetId,
531         test_GetType,
532         test_GetName,
533         test_GetProgress_preTransfer,
534         test_GetState,
535         test_ResumeEmpty,
536         0
537     };
538     static const test_t tests_bits20[] = {
539         test_AddFile,
540         test_AddFileSet,
541         test_EnumFiles,
542         test_CompleteLocal,
543         test_CompleteLocalURL,
544         0
545     };
546     const test_t *test;
547
548     if (!init_paths())
549         return;
550
551     CoInitialize(NULL);
552
553     for (test = tests; *test; ++test)
554     {
555         /* Keep state separate between tests. */
556         if (!setup())
557         {
558             skip("Unable to setup test\n");
559             break;
560         }
561         (*test)();
562         teardown();
563     }
564
565     if (check_bits20())
566     {
567         for (test = tests_bits20; *test; ++test)
568         {
569             /* Keep state separate between tests. */
570             if (!setup())
571             {
572                 skip("Unable to setup test\n");
573                 break;
574             }
575             (*test)();
576             teardown();
577         }
578     }
579     else
580     {
581         win_skip("Tests need BITS 2.0 or higher\n");
582     }
583
584     CoUninitialize();
585 }