xmllite: Add IXmlReaderInput stub implementation.
[wine] / dlls / xmllite / tests / reader.c
1 /*
2  * XMLLite IXmlReader tests
3  *
4  * Copyright 2010 (C) Nikolay Sivov
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 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "initguid.h"
29 #include "ole2.h"
30 #include "xmllite.h"
31 #include "wine/test.h"
32
33 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
34
35 HRESULT WINAPI (*pCreateXmlReader)(REFIID riid, void **ppvObject, IMalloc *pMalloc);
36 HRESULT WINAPI (*pCreateXmlReaderInputWithEncodingName)(IUnknown *stream,
37                                                         IMalloc *pMalloc,
38                                                         LPCWSTR encoding,
39                                                         BOOL hint,
40                                                         LPCWSTR base_uri,
41                                                         IXmlReaderInput **ppInput);
42 static const char *debugstr_guid(REFIID riid)
43 {
44     static char buf[50];
45
46     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
47             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
48             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
49             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
50
51     return buf;
52 }
53
54 typedef struct input_iids_t {
55     IID iids[10];
56     int count;
57 } input_iids_t;
58
59 static const IID *setinput_full[] = {
60     &IID_IXmlReaderInput,
61     &IID_ISequentialStream,
62     &IID_IStream
63 };
64
65 static input_iids_t input_iids;
66
67 static void ok_iids_(const input_iids_t *iids, const IID **expected, int size, int todo, int line)
68 {
69     int i;
70
71     if (todo) {
72         todo_wine
73             ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
74     }
75     else
76        ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
77
78     if (iids->count != size) return;
79
80     for (i = 0; i < size; i++) {
81         ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]),
82              "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
83     }
84 }
85 #define ok_iids(got, exp, size, todo) ok_iids_(got, exp, size, todo, __LINE__)
86
87 typedef struct _testinput
88 {
89     const IUnknownVtbl *lpVtbl;
90     LONG ref;
91 } testinput;
92
93 static inline testinput *impl_from_IUnknown(IUnknown *iface)
94 {
95     return (testinput *)((char*)iface - FIELD_OFFSET(testinput, lpVtbl));
96 }
97
98 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
99 {
100     if (IsEqualGUID( riid, &IID_IUnknown ))
101     {
102         *ppvObj = iface;
103         IUnknown_AddRef(iface);
104         return S_OK;
105     }
106
107     input_iids.iids[input_iids.count++] = *riid;
108
109     *ppvObj = NULL;
110
111     return E_NOINTERFACE;
112 }
113
114 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
115 {
116     testinput *This = impl_from_IUnknown(iface);
117     return InterlockedIncrement(&This->ref);
118 }
119
120 static ULONG WINAPI testinput_Release(IUnknown *iface)
121 {
122     testinput *This = impl_from_IUnknown(iface);
123     LONG ref;
124
125     ref = InterlockedDecrement(&This->ref);
126     if (ref == 0)
127     {
128         HeapFree(GetProcessHeap(), 0, This);
129     }
130
131     return ref;
132 }
133
134 static const struct IUnknownVtbl testinput_vtbl =
135 {
136     testinput_QueryInterface,
137     testinput_AddRef,
138     testinput_Release
139 };
140
141 static HRESULT testinput_createinstance(void **ppObj)
142 {
143     testinput *input;
144
145     input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
146     if(!input) return E_OUTOFMEMORY;
147
148     input->lpVtbl = &testinput_vtbl;
149     input->ref = 1;
150
151     *ppObj = &input->lpVtbl;
152
153     return S_OK;
154 }
155
156 static BOOL init_pointers(void)
157 {
158     /* don't free module here, it's to be unloaded on exit */
159     HMODULE mod = LoadLibraryA("xmllite.dll");
160
161     if (!mod)
162     {
163         win_skip("xmllite library not available\n");
164         return FALSE;
165     }
166
167 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
168     MAKEFUNC(CreateXmlReader);
169     MAKEFUNC(CreateXmlReaderInputWithEncodingName);
170 #undef MAKEFUNC
171
172     return TRUE;
173 }
174
175 static void test_reader_create(void)
176 {
177     HRESULT hr;
178     IXmlReader *reader;
179     IMalloc *imalloc;
180     IUnknown *input;
181
182     /* crashes native */
183     if (0)
184     {
185         hr = pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
186         hr = pCreateXmlReader(NULL, (LPVOID*)&reader, NULL);
187     }
188
189     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
190     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
191
192     hr = CoGetMalloc(1, &imalloc);
193     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
194
195     hr = IMalloc_DidAlloc(imalloc, reader);
196     ok(hr != 1, "Expected 0 or -1, got %08x\n", hr);
197
198     /* test input interface selection sequence */
199     hr = testinput_createinstance((void**)&input);
200     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
201
202     input_iids.count = 0;
203     hr = IXmlReader_SetInput(reader, input);
204     todo_wine ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
205     ok_iids(&input_iids, setinput_full, sizeof(setinput_full)/sizeof(REFIID), TRUE);
206
207     IUnknown_Release(input);
208
209     IXmlReader_Release(reader);
210 }
211
212 static void test_readerinput(void)
213 {
214     IXmlReaderInput *reader_input;
215     IUnknown *obj;
216     IStream *stream;
217     HRESULT hr;
218     LONG ref;
219
220     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
221     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
222     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
223     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
224
225     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
226     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
227
228     ref = IStream_AddRef(stream);
229     ok(ref == 2, "Expected 2, got %d\n", ref);
230     IStream_Release(stream);
231     hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
232     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
233
234     /* IXmlReader grabs a stream reference */
235     ref = IStream_AddRef(stream);
236     todo_wine ok(ref == 3, "Expected 3, got %d\n", ref);
237     IStream_Release(stream);
238
239     /* IID_IXmlReaderInput */
240     /* it returns a kind of private undocumented vtable incompatible with IUnknown,
241        so it's not a COM interface actually.
242        Such query will be used only to check if input is really IXmlReaderInput */
243     obj = (IUnknown*)0xdeadbeef;
244     hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
245     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
246     ref = IUnknown_AddRef(reader_input);
247     ok(ref == 3, "Expected 3, got %d\n", ref);
248     IUnknown_Release(reader_input);
249
250     IUnknown_Release(reader_input);
251     IStream_Release(stream);
252 }
253
254 START_TEST(reader)
255 {
256     HRESULT r;
257
258     r = CoInitialize( NULL );
259     ok( r == S_OK, "failed to init com\n");
260
261     if (!init_pointers())
262     {
263        CoUninitialize();
264        return;
265     }
266
267     test_reader_create();
268     test_readerinput();
269
270     CoUninitialize();
271 }