2 * XMLLite IXmlReader tests
4 * Copyright 2010 (C) Nikolay Sivov
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.
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.
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
31 #include "wine/test.h"
33 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
35 HRESULT WINAPI (*pCreateXmlReader)(REFIID riid, void **ppvObject, IMalloc *pMalloc);
36 HRESULT WINAPI (*pCreateXmlReaderInputWithEncodingName)(IUnknown *stream,
41 IXmlReaderInput **ppInput);
42 static const char *debugstr_guid(REFIID riid)
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]);
54 static const char xmldecl_full[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
56 static IStream *create_stream_on_data(const char *data, int size)
58 IStream *stream = NULL;
63 hglobal = GlobalAlloc(GHND, size);
64 ptr = GlobalLock(hglobal);
66 memcpy(ptr, data, size);
68 hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
69 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
70 ok(stream != NULL, "Expected non-NULL stream\n");
72 GlobalUnlock(hglobal);
77 static void ok_pos_(IXmlReader *reader, int line, int pos, int todo, int _line_)
82 hr = IXmlReader_GetLineNumber(reader, &l);
83 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
84 hr = IXmlReader_GetLinePosition(reader, &p);
85 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
89 ok_(__FILE__, _line_)(l == line && pos == p,
90 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
93 ok_(__FILE__, _line_)(l == line && pos == p,
94 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
97 #define ok_pos(reader, l, p, todo) ok_pos_(reader, l, p, todo, __LINE__)
99 typedef struct input_iids_t {
104 static const IID *setinput_full[] = {
105 &IID_IXmlReaderInput,
107 &IID_ISequentialStream,
111 /* this applies to early xmllite versions */
112 static const IID *setinput_full_old[] = {
113 &IID_IXmlReaderInput,
114 &IID_ISequentialStream,
119 /* after ::SetInput(IXmlReaderInput*) */
120 static const IID *setinput_readerinput[] = {
122 &IID_ISequentialStream,
126 static const IID *empty_seq[] = {
130 static input_iids_t input_iids;
132 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line)
136 while (expected[i++]) size++;
140 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
143 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
145 if (iids->count != size) return;
147 for (i = 0; i < size; i++) {
148 ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
149 (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
150 "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
153 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
155 static const char *state_to_str(XmlReadState state)
157 static const char* state_names[] = {
158 "XmlReadState_Initial",
159 "XmlReadState_Interactive",
160 "XmlReadState_Error",
161 "XmlReadState_EndOfFile",
162 "XmlReadState_Closed"
165 static const char unknown[] = "unknown";
169 case XmlReadState_Initial:
170 case XmlReadState_Interactive:
171 case XmlReadState_Error:
172 case XmlReadState_EndOfFile:
173 case XmlReadState_Closed:
174 return state_names[state];
180 static const char *type_to_str(XmlNodeType type)
182 static const char* type_names[] = {
184 "XmlNodeType_Element",
185 "XmlNodeType_Attribute",
188 "XmlNodeType_ProcessingInstruction",
189 "XmlNodeType_Comment",
190 "XmlNodeType_DocumentType",
191 "XmlNodeType_Whitespace",
192 "XmlNodeType_EndElement",
193 "XmlNodeType_XmlDeclaration"
196 static const char unknown[] = "unknown";
200 case XmlNodeType_None:
201 case XmlNodeType_Element:
202 case XmlNodeType_Attribute:
203 case XmlNodeType_Text:
204 case XmlNodeType_CDATA:
205 case XmlNodeType_ProcessingInstruction:
206 case XmlNodeType_Comment:
207 case XmlNodeType_DocumentType:
208 case XmlNodeType_Whitespace:
209 case XmlNodeType_EndElement:
210 case XmlNodeType_XmlDeclaration:
211 return type_names[type];
217 static void test_read_state_(IXmlReader *reader, XmlReadState expected, int todo, int line)
222 state = -1; /* invalid value */
223 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
224 ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
229 ok_(__FILE__, line)(state == expected, "Expected (%s), got (%s)\n",
230 state_to_str(expected), state_to_str(state));
233 ok_(__FILE__, line)(state == expected, "Expected (%s), got (%s)\n",
234 state_to_str(expected), state_to_str(state));
237 #define test_read_sate(reader, exp, todo) test_read_state_(reader, exp, todo, __LINE__)
239 typedef struct _testinput
241 const IUnknownVtbl *lpVtbl;
245 static inline testinput *impl_from_IUnknown(IUnknown *iface)
247 return (testinput *)((char*)iface - FIELD_OFFSET(testinput, lpVtbl));
250 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
252 if (IsEqualGUID( riid, &IID_IUnknown ))
255 IUnknown_AddRef(iface);
259 input_iids.iids[input_iids.count++] = *riid;
263 return E_NOINTERFACE;
266 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
268 testinput *This = impl_from_IUnknown(iface);
269 return InterlockedIncrement(&This->ref);
272 static ULONG WINAPI testinput_Release(IUnknown *iface)
274 testinput *This = impl_from_IUnknown(iface);
277 ref = InterlockedDecrement(&This->ref);
280 HeapFree(GetProcessHeap(), 0, This);
286 static const struct IUnknownVtbl testinput_vtbl =
288 testinput_QueryInterface,
293 static HRESULT testinput_createinstance(void **ppObj)
297 input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
298 if(!input) return E_OUTOFMEMORY;
300 input->lpVtbl = &testinput_vtbl;
303 *ppObj = &input->lpVtbl;
308 static BOOL init_pointers(void)
310 /* don't free module here, it's to be unloaded on exit */
311 HMODULE mod = LoadLibraryA("xmllite.dll");
315 win_skip("xmllite library not available\n");
319 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
320 MAKEFUNC(CreateXmlReader);
321 MAKEFUNC(CreateXmlReaderInputWithEncodingName);
327 static void test_reader_create(void)
336 hr = pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
337 hr = pCreateXmlReader(NULL, (LPVOID*)&reader, NULL);
340 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
341 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
343 test_read_sate(reader, XmlReadState_Closed, FALSE);
345 /* Null input pointer, releases previous input */
346 hr = IXmlReader_SetInput(reader, NULL);
347 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
349 test_read_sate(reader, XmlReadState_Closed, FALSE);
351 /* test input interface selection sequence */
352 hr = testinput_createinstance((void**)&input);
353 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
355 input_iids.count = 0;
356 hr = IXmlReader_SetInput(reader, input);
357 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
358 ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
360 IUnknown_Release(input);
362 IXmlReader_Release(reader);
365 static void test_readerinput(void)
367 IXmlReaderInput *reader_input;
368 IXmlReader *reader, *reader2;
369 IUnknown *obj, *input;
374 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
375 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
376 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
377 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
379 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
380 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
382 ref = IStream_AddRef(stream);
383 ok(ref == 2, "Expected 2, got %d\n", ref);
384 IStream_Release(stream);
385 hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
386 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
388 /* IXmlReaderInput grabs a stream reference */
389 ref = IStream_AddRef(stream);
390 ok(ref == 3, "Expected 3, got %d\n", ref);
391 IStream_Release(stream);
393 /* try ::SetInput() with valid IXmlReaderInput */
394 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
395 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
397 ref = IUnknown_AddRef(reader_input);
398 ok(ref == 2, "Expected 2, got %d\n", ref);
399 IUnknown_Release(reader_input);
401 hr = IXmlReader_SetInput(reader, reader_input);
402 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
404 test_read_sate(reader, XmlReadState_Initial, FALSE);
406 /* IXmlReader grabs a IXmlReaderInput reference */
407 ref = IUnknown_AddRef(reader_input);
408 ok(ref == 3, "Expected 3, got %d\n", ref);
409 IUnknown_Release(reader_input);
411 ref = IStream_AddRef(stream);
412 ok(ref == 4, "Expected 4, got %d\n", ref);
413 IStream_Release(stream);
415 /* reset input and check state */
416 hr = IXmlReader_SetInput(reader, NULL);
417 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
419 test_read_sate(reader, XmlReadState_Closed, FALSE);
421 IXmlReader_Release(reader);
423 ref = IStream_AddRef(stream);
424 ok(ref == 3, "Expected 3, got %d\n", ref);
425 IStream_Release(stream);
427 ref = IUnknown_AddRef(reader_input);
428 ok(ref == 2, "Expected 2, got %d\n", ref);
429 IUnknown_Release(reader_input);
431 /* IID_IXmlReaderInput */
432 /* it returns a kind of private undocumented vtable incompatible with IUnknown,
433 so it's not a COM interface actually.
434 Such query will be used only to check if input is really IXmlReaderInput */
435 obj = (IUnknown*)0xdeadbeef;
436 hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
437 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
438 ref = IUnknown_AddRef(reader_input);
439 ok(ref == 3, "Expected 3, got %d\n", ref);
440 IUnknown_Release(reader_input);
442 IUnknown_Release(reader_input);
443 IStream_Release(stream);
445 /* test input interface selection sequence */
446 hr = testinput_createinstance((void**)&input);
447 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
449 input_iids.count = 0;
450 ref = IUnknown_AddRef(input);
451 ok(ref == 2, "Expected 2, got %d\n", ref);
452 IUnknown_Release(input);
453 hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
454 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
455 ok_iids(&input_iids, empty_seq, NULL, FALSE);
456 /* IXmlReaderInput stores stream interface as IUnknown */
457 ref = IUnknown_AddRef(input);
458 ok(ref == 3, "Expected 3, got %d\n", ref);
459 IUnknown_Release(input);
461 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
462 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
464 input_iids.count = 0;
465 ref = IUnknown_AddRef(reader_input);
466 ok(ref == 2, "Expected 2, got %d\n", ref);
467 IUnknown_Release(reader_input);
468 ref = IUnknown_AddRef(input);
469 ok(ref == 3, "Expected 3, got %d\n", ref);
470 IUnknown_Release(input);
471 hr = IXmlReader_SetInput(reader, reader_input);
472 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
473 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
475 test_read_sate(reader, XmlReadState_Closed, FALSE);
477 ref = IUnknown_AddRef(input);
478 ok(ref == 3, "Expected 3, got %d\n", ref);
479 IUnknown_Release(input);
481 ref = IUnknown_AddRef(reader_input);
482 ok(ref == 2, "Expected 2, got %d\n", ref);
483 IUnknown_Release(reader_input);
484 /* repeat another time, no check or caching here */
485 input_iids.count = 0;
486 hr = IXmlReader_SetInput(reader, reader_input);
487 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
488 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
491 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
492 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
494 /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
495 ::SetInput() level, each time it's called */
496 input_iids.count = 0;
497 hr = IXmlReader_SetInput(reader2, reader_input);
498 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
499 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
501 IXmlReader_Release(reader2);
502 IXmlReader_Release(reader);
504 IUnknown_Release(reader_input);
505 IUnknown_Release(input);
508 static void test_reader_state(void)
513 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
514 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
516 /* invalid arguments */
517 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
518 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
520 IXmlReader_Release(reader);
523 static void test_read_xmldeclaration(void)
531 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
532 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
534 /* position methods with Null args */
535 hr = IXmlReader_GetLineNumber(reader, NULL);
536 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
538 hr = IXmlReader_GetLinePosition(reader, NULL);
539 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
541 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
543 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
544 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
546 ok_pos(reader, 0, 0, FALSE);
549 hr = IXmlReader_Read(reader, &type);
551 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
552 ok(type == XmlNodeType_XmlDeclaration,
553 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
555 ok_pos(reader, 1, 55, TRUE);
557 /* check attributes */
558 hr = IXmlReader_MoveToNextAttribute(reader);
559 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
560 ok_pos(reader, 1, 55, TRUE);
562 hr = IXmlReader_MoveToFirstAttribute(reader);
563 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
564 ok_pos(reader, 1, 55, TRUE);
566 hr = IXmlReader_GetAttributeCount(reader, &count);
568 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
569 ok(count == 3, "Expected 3, got %d\n", count);
571 hr = IXmlReader_GetDepth(reader, &count);
573 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
574 ok(count == 1, "Expected 1, got %d\n", count);
577 IStream_Release(stream);
578 IXmlReader_Release(reader);
585 r = CoInitialize( NULL );
586 ok( r == S_OK, "failed to init com\n");
588 if (!init_pointers())
594 test_reader_create();
597 test_read_xmldeclaration();