Report BINDSTATUS_SENDINGREQUEST in FileProtocol::Start.
[wine] / dlls / urlmon / tests / protocol.c
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define COBJMACROS
20
21 #include <wine/test.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "urlmon.h"
28
29 #include "initguid.h"
30
31 #define DEFINE_EXPECT(func) \
32     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
33
34 #define SET_EXPECT(func) \
35     expect_ ## func = TRUE
36
37 #define CHECK_EXPECT(func) \
38     ok(expect_ ##func, "unexpected call\n"); \
39     expect_ ## func = FALSE; \
40     called_ ## func = TRUE
41
42 #define CHECK_EXPECT2(func) \
43     ok(expect_ ##func, "unexpected call\n"); \
44     called_ ## func = TRUE
45
46 #define CHECK_CALLED(func) \
47     ok(called_ ## func, "expected " #func "\n"); \
48     expect_ ## func = called_ ## func = FALSE
49
50 DEFINE_EXPECT(GetBindInfo);
51 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
52 DEFINE_EXPECT(ReportProgress_DIRECTBIND);
53 DEFINE_EXPECT(ReportProgress_SENDINGREQUEST);
54 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
55 DEFINE_EXPECT(ReportData);
56 DEFINE_EXPECT(ReportResult);
57
58 static HRESULT expect_hrResult;
59 static LPCWSTR file_name;
60
61 static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
62 {
63     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
64         *ppv = iface;
65         return S_OK;
66     }
67     return E_NOINTERFACE;
68 }
69
70 static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface)
71 {
72     return 2;
73 }
74
75 static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface)
76 {
77     return 1;
78 }
79
80 static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
81 {
82     ok(0, "unexpected call\n");
83     return E_NOTIMPL;
84 }
85
86 static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
87         LPCWSTR szStatusText)
88 {
89     static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0};
90
91     switch(ulStatusCode) {
92         case BINDSTATUS_MIMETYPEAVAILABLE:
93             CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
94             if(szStatusText)
95                 ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
96         case BINDSTATUS_DIRECTBIND:
97             CHECK_EXPECT2(ReportProgress_DIRECTBIND);
98             if(szStatusText)
99                 ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
100             break;
101         case BINDSTATUS_CACHEFILENAMEAVAILABLE:
102             CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
103             if(szStatusText)
104                 ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n");
105             break;
106         case BINDSTATUS_SENDINGREQUEST:
107             CHECK_EXPECT(ReportProgress_SENDINGREQUEST);
108             ok(szStatusText != NULL, "szStatusText == NULL\n");
109             if(szStatusText)
110                 ok(!*szStatusText, "wrong szStatusText\n");
111             break;
112         default:
113             ok(0, "Unexpected call %ld\n", ulStatusCode);
114     };
115
116     return S_OK;
117 }
118
119 static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
120         ULONG ulProgress, ULONG ulProgressMax)
121 {
122     CHECK_EXPECT(ReportData);
123
124     ok(ulProgress == ulProgressMax, "ulProgress != ulProgressMax\n");
125     ok(ulProgressMax == 13, "ulProgressMax=%ld, expected 13\n", ulProgressMax);
126     ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION),
127             "grcf = %08lx\n", grfBSCF);
128
129     return S_OK;
130 }
131
132 static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
133         DWORD dwError, LPCWSTR szResult)
134 {
135     CHECK_EXPECT(ReportResult);
136
137     ok(hrResult == expect_hrResult, "hrResult = %08lx, expected: %08lx\n",
138             hrResult, expect_hrResult);
139     if(SUCCEEDED(hrResult))
140         ok(dwError == ERROR_SUCCESS, "dwError = %ld, expected ERROR_SUCCESS\n", dwError);
141     else
142         ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n");
143     ok(!szResult, "szResult != NULL\n");
144
145     return S_OK;
146 }
147
148 static IInternetProtocolSinkVtbl protocol_sink_vtbl = {
149     ProtocolSink_QueryInterface,
150     ProtocolSink_AddRef,
151     ProtocolSink_Release,
152     ProtocolSink_Switch,
153     ProtocolSink_ReportProgress,
154     ProtocolSink_ReportData,
155     ProtocolSink_ReportResult
156 };
157
158 static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl };
159
160 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
161 {
162     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) {
163         *ppv = iface;
164         return S_OK;
165     }
166     return E_NOINTERFACE;
167 }
168
169 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
170 {
171     return 2;
172 }
173
174 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
175 {
176     return 1;
177 }
178
179 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
180 {
181     CHECK_EXPECT(GetBindInfo);
182
183     ok(grfBINDF != NULL, "grfBINDF == NULL\n");
184     if(grfBINDF)
185         ok(!*grfBINDF, "*grfBINDF != 0\n");
186     ok(pbindinfo != NULL, "pbindinfo == NULL\n");
187     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %ld\n", pbindinfo->cbSize);
188
189     return S_OK;
190 }
191
192 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
193         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
194 {
195     ok(0, "unexpected call\n");
196     return E_NOTIMPL;
197 }
198
199 static IInternetBindInfoVtbl bind_info_vtbl = {
200     BindInfo_QueryInterface,
201     BindInfo_AddRef,
202     BindInfo_Release,
203     BindInfo_GetBindInfo,
204     BindInfo_GetBindString
205 };
206
207 static IInternetBindInfo bind_info = { &bind_info_vtbl };
208
209 static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first)
210 {
211     HRESULT hres;
212
213     SET_EXPECT(GetBindInfo);
214     SET_EXPECT(ReportProgress_DIRECTBIND);
215     if(is_first) {
216         SET_EXPECT(ReportProgress_SENDINGREQUEST);
217         SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
218         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
219         SET_EXPECT(ReportResult);
220     }
221     SET_EXPECT(ReportData);
222  
223     expect_hrResult = S_OK;
224
225     hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0);
226     ok(hres == S_OK, "Start failed: %08lx\n", hres);
227
228     CHECK_CALLED(GetBindInfo);
229     CHECK_CALLED(ReportProgress_DIRECTBIND);
230     if(is_first) {
231         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
232         CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
233         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
234         CHECK_CALLED(ReportResult);
235     }
236     CHECK_CALLED(ReportData);
237 }
238
239 static void test_file_protocol_url(LPCWSTR url)
240 {
241     IInternetProtocolInfo *protocol_info;
242     IUnknown *unk;
243     IClassFactory *factory;
244     HRESULT hres;
245
246     hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL,
247             &IID_IUnknown, (void**)&unk);
248     ok(hres == S_OK, "CoGetClassObject failed: %08lx\n", hres);
249     if(!SUCCEEDED(hres))
250         return;
251
252     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
253     ok(hres == E_NOINTERFACE,
254             "Could not get IInternetProtocolInfo interface: %08lx, expected E_NOINTERFACE\n", hres);
255
256     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
257     ok(hres == S_OK, "Could not get IClassFactory interface\n");
258     if(SUCCEEDED(hres)) {
259         IInternetProtocol *protocol;
260         BYTE buf[512];
261         ULONG cb;
262         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
263         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
264
265         if(SUCCEEDED(hres)) {
266             file_protocol_start(protocol, url, TRUE);
267             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
268             ok(hres == S_OK, "Read failed: %08lx\n", hres);
269             ok(cb == 2, "cb=%lu expected 2\n", cb);
270             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
271             ok(hres == S_FALSE, "Read failed: %08lx\n", hres);
272             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
273             ok(hres == S_FALSE, "Read failed: %08lx expected S_FALSE\n", hres);
274             ok(cb == 0, "cb=%lu expected 0\n", cb);
275             hres = IInternetProtocol_UnlockRequest(protocol);
276             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
277
278             file_protocol_start(protocol, url, FALSE);
279             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
280             ok(hres == S_FALSE, "Read failed: %08lx\n", hres);
281             hres = IInternetProtocol_LockRequest(protocol, 0);
282             ok(hres == S_OK, "LockRequest failed: %08lx\n", hres);
283             hres = IInternetProtocol_UnlockRequest(protocol);
284             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
285
286             IInternetProtocol_Release(protocol);
287         }
288
289         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
290         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
291
292         if(SUCCEEDED(hres)) {
293             file_protocol_start(protocol, url, TRUE);
294             hres = IInternetProtocol_LockRequest(protocol, 0);
295             ok(hres == S_OK, "LockRequest failed: %08lx\n", hres);
296             hres = IInternetProtocol_Terminate(protocol, 0);
297             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
298             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
299             ok(hres == S_OK, "Read failed: %08lx\n\n", hres);
300             hres = IInternetProtocol_UnlockRequest(protocol);
301             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
302             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
303             ok(hres == S_OK, "Read failed: %08lx\n", hres);
304             hres = IInternetProtocol_Terminate(protocol, 0);
305             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
306
307             IInternetProtocol_Release(protocol);
308         }
309
310         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
311         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
312
313         if(SUCCEEDED(hres)) {
314             file_protocol_start(protocol, url, TRUE);
315             hres = IInternetProtocol_Terminate(protocol, 0);
316             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
317             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
318             ok(hres == S_OK, "Read failed: %08lx\n", hres);
319             ok(cb == 2, "cb=%lu expected 2\n", cb);
320
321             IInternetProtocol_Release(protocol);
322         }
323
324         IClassFactory_Release(factory);
325     }
326
327     IUnknown_Release(unk);
328 }
329
330 static void test_file_protocol(void) {
331     IInternetProtocol *protocol;
332     WCHAR buf[MAX_PATH];
333     DWORD size;
334     ULONG len;
335     HANDLE file;
336     HRESULT hres;
337
338     static const WCHAR index_url[] =
339         {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
340     static const WCHAR index_url2[] =
341         {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0};
342     static const WCHAR wszFile[] = {'f','i','l','e',':',0};
343     static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
344     static const char html_doc[] = "<HTML></HTML>";
345
346     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
347             FILE_ATTRIBUTE_NORMAL, NULL);
348     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
349     if(file == INVALID_HANDLE_VALUE)
350         return;
351     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
352     CloseHandle(file);
353
354     file_name = wszIndexHtml;
355     test_file_protocol_url(index_url);
356
357     memcpy(buf, wszFile, sizeof(wszFile));
358     len = sizeof(wszFile)/sizeof(WCHAR)-1;
359     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
360     buf[len++] = '\\';
361     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
362
363     file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1;
364     test_file_protocol_url(buf);
365
366     DeleteFileW(wszIndexHtml);
367
368     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
369             &IID_IInternetProtocol, (void**)&protocol);
370     ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres);
371     if(FAILED(hres))
372         return;
373
374     SET_EXPECT(GetBindInfo);
375     expect_hrResult = MK_E_SYNTAX;
376     hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0);
377     ok(hres == MK_E_SYNTAX, "Start failed: %08lx, expected MK_E_SYNTAX\n", hres);
378     CHECK_CALLED(GetBindInfo);
379
380     SET_EXPECT(GetBindInfo);
381     SET_EXPECT(ReportProgress_DIRECTBIND);
382     SET_EXPECT(ReportProgress_SENDINGREQUEST);
383     SET_EXPECT(ReportResult);
384     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
385     hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0);
386     ok(hres == INET_E_RESOURCE_NOT_FOUND,
387             "Start failed: %08lx expected INET_E_RESOURCE_NOT_FOUND\n", hres);
388     CHECK_CALLED(GetBindInfo);
389     CHECK_CALLED(ReportProgress_DIRECTBIND);
390     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
391     CHECK_CALLED(ReportResult);
392
393     IInternetProtocol_Release(protocol);
394
395     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
396             &IID_IInternetProtocol, (void**)&protocol);
397     ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres);
398     if(FAILED(hres))
399         return;
400
401     SET_EXPECT(GetBindInfo);
402     SET_EXPECT(ReportProgress_DIRECTBIND);
403     SET_EXPECT(ReportProgress_SENDINGREQUEST);
404     SET_EXPECT(ReportResult);
405     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
406     hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0);
407     ok(hres == INET_E_RESOURCE_NOT_FOUND,
408             "Start failed: %08lx, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
409     CHECK_CALLED(GetBindInfo);
410     CHECK_CALLED(ReportProgress_DIRECTBIND);
411     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
412     CHECK_CALLED(ReportResult);
413
414     IInternetProtocol_Release(protocol);
415 }
416
417 START_TEST(protocol)
418 {
419     OleInitialize(NULL);
420
421     test_file_protocol();
422
423     OleUninitialize();
424 }