Reverse the order for deleting the items in resetcontent to correctly
[wine] / dlls / urlmon / tests / url.c
1 /*
2  * UrlMon URL tests
3  *
4  * Copyright 2004 Kevin Koltzau
5  * Copyright 2004 Jacek Caban
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "urlmon.h"
29
30 #include "wine/test.h"
31
32 #ifdef NONAMELESSUNION
33 # define U(x)  (x).u
34 #else
35 # define U(x)  (x)
36 #endif
37
38 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
39 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
40
41 static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
42                                        'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
43 static BOOL stopped_binding = FALSE;
44
45 static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2)
46 {
47     HRESULT hr;
48     IMoniker *mon1 = NULL;
49     IMoniker *mon2 = NULL;
50
51     hr = CreateURLMoniker(NULL, url1, &mon1);
52     ok(SUCCEEDED(hr), "failed to create moniker: 0x%08lx\n", hr);
53     if(SUCCEEDED(hr)) {
54         hr = CreateURLMoniker(mon1, url2, &mon2);
55         ok(SUCCEEDED(hr), "failed to create moniker: 0x%08lx\n", hr);
56     }
57     if(mon1) IMoniker_Release(mon1);
58     if(mon2) IMoniker_Release(mon2);
59 }
60
61 static void test_create()
62 {
63     test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1);
64 }
65
66 typedef struct {
67     IBindStatusCallbackVtbl *lpVtbl;
68     ULONG ref;
69     IBinding *pbind;
70     IStream *pstr;
71 } statusclb;
72
73 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppvObject)
74 {
75     return E_NOINTERFACE;
76 }
77
78 static ULONG WINAPI statusclb_AddRef(IBindStatusCallback *iface)
79 {
80     return InterlockedIncrement(&((statusclb*)iface)->ref);
81 }
82
83 static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface)
84 {
85     statusclb *This = (statusclb*)iface;
86     ULONG ref;
87     ref = InterlockedDecrement(&This->ref);
88     if(!ref)
89         HeapFree(GetProcessHeap(), 0, This);
90     return ref;
91 }
92
93 static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, IBinding *pib)
94 {
95     statusclb *This = (statusclb*)iface;
96
97     This->pbind = pib;
98     ok(pib != NULL, "pib should not be NULL\n");
99     if(pib)
100         IBinding_AddRef(pib);
101
102     return S_OK;
103 }
104
105 static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
106 {
107     return E_NOTIMPL;
108 }
109
110 static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
111 {
112     return E_NOTIMPL;
113 }
114
115 static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, ULONG ulProgressMax,
116                            ULONG ulStatusCode, LPCWSTR szStatusText)
117 {
118     return S_OK;
119 }
120
121 static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
122 {
123     statusclb *This = (statusclb*)iface;
124
125     ok(SUCCEEDED(hresult), "Download failed: %08lx\n", hresult);
126     ok(szError == NULL, "szError should be NULL\n");
127     stopped_binding = TRUE;
128     IBinding_Release(This->pbind);
129     ok(This->pstr != NULL, "pstr should not be NULL here\n");
130     if(This->pstr)
131         IStream_Release(This->pstr);
132
133     return S_OK;
134 }
135
136 static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
137 {
138     DWORD cbSize;
139
140     *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
141     cbSize = pbindinfo->cbSize;
142     memset(pbindinfo, 0, cbSize);
143     pbindinfo->cbSize = cbSize;
144
145     return S_OK;
146 }
147
148 static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, DWORD dwSize,
149                                                 FORMATETC* pformatetc, STGMEDIUM* pstgmed)
150 {
151     statusclb *This = (statusclb*)iface;
152     HRESULT hres;
153     DWORD readed;
154     BYTE buf[512];
155     if(!This->pstr) {
156         ok(grfBSCF & BSCF_FIRSTDATANOTIFICATION, "pstr should be set when BSCF_FIRSTDATANOTIFICATION\n");
157         This->pstr = U(*pstgmed).pstm;
158         IStream_AddRef(This->pstr);
159         ok(This->pstr != NULL, "pstr should not be NULL here\n");
160     }
161
162     do hres = IStream_Read(This->pstr, buf, 512, &readed);
163     while(hres == S_OK);
164     ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08lx\n", hres);
165
166     return S_OK;
167 }
168
169 static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
170 {
171     return E_NOTIMPL;
172 }
173
174 static IBindStatusCallbackVtbl statusclbVtbl = {
175     statusclb_QueryInterface,
176     statusclb_AddRef,
177     statusclb_Release,
178     statusclb_OnStartBinding,
179     statusclb_GetPriority,
180     statusclb_OnLowResource,
181     statusclb_OnProgress,
182     statusclb_OnStopBinding,
183     statusclb_GetBindInfo,
184     statusclb_OnDataAvailable,
185     statusclb_OnObjectAvailable
186 };
187
188 static IBindStatusCallback* statusclb_create()
189 {
190     statusclb *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(statusclb));
191     ret->lpVtbl = &statusclbVtbl;
192     ret->ref = 1;
193     ret->pbind = NULL;
194     ret->pstr = NULL;
195     return (IBindStatusCallback*)ret;
196 }
197
198 static void test_CreateAsyncBindCtx()
199 {
200     IBindCtx *bctx = (IBindCtx*)0x0ff00ff0;
201     HRESULT hres;
202     ULONG ref;
203     BIND_OPTS bindopts;
204     IBindStatusCallback *bsc = statusclb_create();
205
206     hres = CreateAsyncBindCtx(0, NULL, NULL, &bctx);
207     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08lx\n", hres);
208     ok(bctx == (IBindCtx*)0x0ff00ff0, "bctx should not be changed\n");
209
210     hres = CreateAsyncBindCtx(0, NULL, NULL, NULL);
211     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08lx\n", hres);
212
213     hres = CreateAsyncBindCtx(0, bsc, NULL, &bctx);
214     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08lx\n", hres);
215     if(FAILED(hres)) {
216         IBindStatusCallback_Release(bsc);
217         return;
218     }
219
220     bindopts.cbStruct = 16;
221     hres = IBindCtx_GetBindOptions(bctx, &bindopts);
222     ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08lx\n", hres);
223     ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
224                 "bindopts.grfFlags = %08lx, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
225     ok(bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
226                 "bindopts.grfMode = %08lx, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n", bindopts.grfMode);
227     ok(bindopts.dwTickCountDeadline == 0,
228                 "bindopts.dwTickCountDeadline = %08lx, expected: 0\n", bindopts.dwTickCountDeadline);
229
230     ref = IBindCtx_Release(bctx);
231     ok(ref == 0, "bctx should be destroyed here\n");
232     ref = IBindStatusCallback_Release(bsc);
233     ok(ref == 0, "bsc should be destroyed here\n");
234 }
235
236 static void test_BindToStorage()
237 {
238     IMoniker *mon;
239     HRESULT hres;
240     LPOLESTR display_name;
241     IBindCtx *bctx;
242     MSG msg;
243     IBindStatusCallback *previousclb, *sclb = statusclb_create();
244     IUnknown *unk = (IUnknown*)0x00ff00ff;
245
246     hres = CreateAsyncBindCtx(0, sclb, NULL, &bctx);
247     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08lx\n\n", hres);
248     if(FAILED(hres)) {
249         IBindStatusCallback_Release(sclb);
250         return;
251     }
252
253     hres = RegisterBindStatusCallback(bctx, sclb, &previousclb, 0);
254     ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08lx\n", hres);
255     ok(previousclb == sclb, "previousclb(%p) != sclb(%p)\n", previousclb, sclb);
256     if(previousclb)
257         IBindStatusCallback_Release(previousclb);
258
259     hres = CreateURLMoniker(NULL, WINE_ABOUT_URL, &mon);
260     ok(SUCCEEDED(hres), "failed to create moniker: %08lx\n", hres);
261     if(FAILED(hres)) {
262         IBindStatusCallback_Release(sclb);
263         IBindCtx_Release(bctx);
264         return;
265     }
266
267     hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
268     ok(SUCCEEDED(hres), "GetDisplayName failed %08lx\n", hres);
269     ok(!lstrcmpW(display_name, WINE_ABOUT_URL), "GetDisplayName got wrong name\n");
270
271     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
272     ok(SUCCEEDED(hres), "IMoniker_BindToStorage failed: %08lx\n", hres);
273     todo_wine {
274         ok(unk == NULL, "istr should be NULL\n");
275     }
276     if(FAILED(hres)) {
277         IBindStatusCallback_Release(sclb);
278         IMoniker_Release(mon);
279         return;
280     }
281     if(unk)
282         IUnknown_Release(unk);
283
284     while(!stopped_binding && GetMessage(&msg,NULL,0,0)) {
285         TranslateMessage(&msg);
286         DispatchMessage(&msg);
287     }
288
289     ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
290     ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
291     ok(IBindStatusCallback_Release(sclb) == 0, "scbl should be destroyed here\n");
292 }
293
294 START_TEST(url)
295 {
296     test_create();
297     test_CreateAsyncBindCtx();
298     test_BindToStorage();
299 }