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
32 #include "wine/test.h"
34 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
36 static HRESULT (WINAPI *pCreateXmlReader)(REFIID riid, void **ppvObject, IMalloc *pMalloc);
37 static HRESULT (WINAPI *pCreateXmlReaderInputWithEncodingName)(IUnknown *stream,
42 IXmlReaderInput **ppInput);
43 static const char *debugstr_guid(REFIID riid)
47 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
48 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
49 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
50 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
55 static const char xmldecl_full[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
57 static IStream *create_stream_on_data(const char *data, int size)
59 IStream *stream = NULL;
64 hglobal = GlobalAlloc(GHND, size);
65 ptr = GlobalLock(hglobal);
67 memcpy(ptr, data, size);
69 hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
70 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
71 ok(stream != NULL, "Expected non-NULL stream\n");
73 GlobalUnlock(hglobal);
78 static void ok_pos_(IXmlReader *reader, int line, int pos, int line_broken,
79 int pos_broken, int todo, int _line_)
85 hr = IXmlReader_GetLineNumber(reader, &l);
86 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
87 hr = IXmlReader_GetLinePosition(reader, &p);
88 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
90 if (line_broken == -1 && pos_broken == -1)
93 broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
94 (pos_broken == -1 ? pos : pos_broken) == p);
98 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
99 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
102 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
103 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
106 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
108 typedef struct input_iids_t {
113 static const IID *setinput_full[] = {
114 &IID_IXmlReaderInput,
116 &IID_ISequentialStream,
120 /* this applies to early xmllite versions */
121 static const IID *setinput_full_old[] = {
122 &IID_IXmlReaderInput,
123 &IID_ISequentialStream,
128 /* after ::SetInput(IXmlReaderInput*) */
129 static const IID *setinput_readerinput[] = {
131 &IID_ISequentialStream,
135 static const IID *empty_seq[] = {
139 static input_iids_t input_iids;
141 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line)
145 while (expected[i++]) size++;
149 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
152 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
154 if (iids->count != size) return;
156 for (i = 0; i < size; i++) {
157 ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
158 (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
159 "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
162 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
164 static const char *state_to_str(XmlReadState state)
166 static const char* state_names[] = {
167 "XmlReadState_Initial",
168 "XmlReadState_Interactive",
169 "XmlReadState_Error",
170 "XmlReadState_EndOfFile",
171 "XmlReadState_Closed"
174 static const char unknown[] = "unknown";
178 case XmlReadState_Initial:
179 case XmlReadState_Interactive:
180 case XmlReadState_Error:
181 case XmlReadState_EndOfFile:
182 case XmlReadState_Closed:
183 return state_names[state];
189 static const char *type_to_str(XmlNodeType type)
191 static const char* type_names[] = {
193 "XmlNodeType_Element",
194 "XmlNodeType_Attribute",
198 "XmlNodeType_ProcessingInstruction",
199 "XmlNodeType_Comment",
201 "XmlNodeType_DocumentType",
203 "XmlNodeType_Whitespace",
205 "XmlNodeType_EndElement",
207 "XmlNodeType_XmlDeclaration"
210 static const char unknown[] = "unknown";
214 case XmlNodeType_None:
215 case XmlNodeType_Element:
216 case XmlNodeType_Attribute:
217 case XmlNodeType_Text:
218 case XmlNodeType_CDATA:
219 case XmlNodeType_ProcessingInstruction:
220 case XmlNodeType_Comment:
221 case XmlNodeType_DocumentType:
222 case XmlNodeType_Whitespace:
223 case XmlNodeType_EndElement:
224 case XmlNodeType_XmlDeclaration:
225 return type_names[type];
231 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
232 XmlReadState exp_broken, int todo, int line)
238 state = -1; /* invalid value */
239 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
240 ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
242 if (exp_broken == -1)
245 broken_state = broken(exp_broken == state);
250 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
251 state_to_str(expected), state_to_str(state));
254 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
255 state_to_str(expected), state_to_str(state));
258 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
260 typedef struct _testinput
262 IUnknown IUnknown_iface;
266 static inline testinput *impl_from_IUnknown(IUnknown *iface)
268 return CONTAINING_RECORD(iface, testinput, IUnknown_iface);
271 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
273 if (IsEqualGUID( riid, &IID_IUnknown ))
276 IUnknown_AddRef(iface);
280 input_iids.iids[input_iids.count++] = *riid;
284 return E_NOINTERFACE;
287 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
289 testinput *This = impl_from_IUnknown(iface);
290 return InterlockedIncrement(&This->ref);
293 static ULONG WINAPI testinput_Release(IUnknown *iface)
295 testinput *This = impl_from_IUnknown(iface);
298 ref = InterlockedDecrement(&This->ref);
301 HeapFree(GetProcessHeap(), 0, This);
307 static const struct IUnknownVtbl testinput_vtbl =
309 testinput_QueryInterface,
314 static HRESULT testinput_createinstance(void **ppObj)
318 input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
319 if(!input) return E_OUTOFMEMORY;
321 input->IUnknown_iface.lpVtbl = &testinput_vtbl;
324 *ppObj = &input->IUnknown_iface;
329 static BOOL init_pointers(void)
331 /* don't free module here, it's to be unloaded on exit */
332 HMODULE mod = LoadLibraryA("xmllite.dll");
336 win_skip("xmllite library not available\n");
340 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
341 MAKEFUNC(CreateXmlReader);
342 MAKEFUNC(CreateXmlReaderInputWithEncodingName);
348 static void test_reader_create(void)
358 pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
359 pCreateXmlReader(NULL, (void**)&reader, NULL);
362 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
363 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
365 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
368 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
369 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
370 ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
373 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
374 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
376 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
377 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
379 /* Null input pointer, releases previous input */
380 hr = IXmlReader_SetInput(reader, NULL);
381 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
383 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
385 /* test input interface selection sequence */
386 hr = testinput_createinstance((void**)&input);
387 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
391 input_iids.count = 0;
392 hr = IXmlReader_SetInput(reader, input);
393 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
394 ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
395 IUnknown_Release(input);
397 IXmlReader_Release(reader);
400 static void test_readerinput(void)
402 IXmlReaderInput *reader_input;
403 IXmlReader *reader, *reader2;
404 IUnknown *obj, *input;
405 IStream *stream, *stream2;
409 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
410 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
411 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
412 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
414 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
415 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
417 ref = IStream_AddRef(stream);
418 ok(ref == 2, "Expected 2, got %d\n", ref);
419 IStream_Release(stream);
420 hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
421 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
423 hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
424 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
426 hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
427 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
429 /* IXmlReaderInput grabs a stream reference */
430 ref = IStream_AddRef(stream);
431 ok(ref == 3, "Expected 3, got %d\n", ref);
432 IStream_Release(stream);
434 /* try ::SetInput() with valid IXmlReaderInput */
435 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
436 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
438 ref = IUnknown_AddRef(reader_input);
439 ok(ref == 2, "Expected 2, got %d\n", ref);
440 IUnknown_Release(reader_input);
442 hr = IXmlReader_SetInput(reader, reader_input);
443 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
445 test_read_state(reader, XmlReadState_Initial, -1, FALSE);
447 /* IXmlReader grabs a IXmlReaderInput reference */
448 ref = IUnknown_AddRef(reader_input);
449 ok(ref == 3, "Expected 3, got %d\n", ref);
450 IUnknown_Release(reader_input);
452 ref = IStream_AddRef(stream);
453 ok(ref == 4, "Expected 4, got %d\n", ref);
454 IStream_Release(stream);
456 /* reset input and check state */
457 hr = IXmlReader_SetInput(reader, NULL);
458 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
460 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
462 IXmlReader_Release(reader);
464 ref = IStream_AddRef(stream);
465 ok(ref == 3, "Expected 3, got %d\n", ref);
466 IStream_Release(stream);
468 ref = IUnknown_AddRef(reader_input);
469 ok(ref == 2, "Expected 2, got %d\n", ref);
470 IUnknown_Release(reader_input);
472 /* IID_IXmlReaderInput */
473 /* it returns a kind of private undocumented vtable incompatible with IUnknown,
474 so it's not a COM interface actually.
475 Such query will be used only to check if input is really IXmlReaderInput */
476 obj = (IUnknown*)0xdeadbeef;
477 hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
478 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
479 ref = IUnknown_AddRef(reader_input);
480 ok(ref == 3, "Expected 3, got %d\n", ref);
481 IUnknown_Release(reader_input);
483 IUnknown_Release(reader_input);
484 IUnknown_Release(reader_input);
485 IStream_Release(stream);
487 /* test input interface selection sequence */
488 hr = testinput_createinstance((void**)&input);
489 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
491 input_iids.count = 0;
492 ref = IUnknown_AddRef(input);
493 ok(ref == 2, "Expected 2, got %d\n", ref);
494 IUnknown_Release(input);
495 hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
496 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
497 ok_iids(&input_iids, empty_seq, NULL, FALSE);
498 /* IXmlReaderInput stores stream interface as IUnknown */
499 ref = IUnknown_AddRef(input);
500 ok(ref == 3, "Expected 3, got %d\n", ref);
501 IUnknown_Release(input);
503 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
504 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
506 input_iids.count = 0;
507 ref = IUnknown_AddRef(reader_input);
508 ok(ref == 2, "Expected 2, got %d\n", ref);
509 IUnknown_Release(reader_input);
510 ref = IUnknown_AddRef(input);
511 ok(ref == 3, "Expected 3, got %d\n", ref);
512 IUnknown_Release(input);
513 hr = IXmlReader_SetInput(reader, reader_input);
514 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
515 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
517 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
519 ref = IUnknown_AddRef(input);
520 ok(ref == 3, "Expected 3, got %d\n", ref);
521 IUnknown_Release(input);
523 ref = IUnknown_AddRef(reader_input);
524 ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
525 "Expected 3, got %d\n", ref);
526 IUnknown_Release(reader_input);
527 /* repeat another time, no check or caching here */
528 input_iids.count = 0;
529 hr = IXmlReader_SetInput(reader, reader_input);
530 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
531 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
534 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
535 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
537 /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
538 ::SetInput() level, each time it's called */
539 input_iids.count = 0;
540 hr = IXmlReader_SetInput(reader2, reader_input);
541 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
542 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
544 IXmlReader_Release(reader2);
545 IXmlReader_Release(reader);
547 IUnknown_Release(reader_input);
548 IUnknown_Release(input);
551 static void test_reader_state(void)
556 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
557 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
559 /* invalid arguments */
560 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
561 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
563 IXmlReader_Release(reader);
566 static void test_read_xmldeclaration(void)
574 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
575 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
577 /* position methods with Null args */
578 hr = IXmlReader_GetLineNumber(reader, NULL);
579 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
581 hr = IXmlReader_GetLinePosition(reader, NULL);
582 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
584 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
586 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
587 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
589 ok_pos(reader, 0, 0, -1, -1, FALSE);
592 hr = IXmlReader_Read(reader, &type);
594 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
595 ok(type == XmlNodeType_XmlDeclaration,
596 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
598 /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
599 ok_pos(reader, 1, 3, -1, 55, TRUE);
601 /* check attributes */
602 hr = IXmlReader_MoveToNextAttribute(reader);
603 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
604 ok_pos(reader, 1, 7, -1, 55, TRUE);
606 hr = IXmlReader_MoveToFirstAttribute(reader);
607 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
608 ok_pos(reader, 1, 7, -1, 55, TRUE);
610 hr = IXmlReader_GetAttributeCount(reader, &count);
612 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
613 ok(count == 3, "Expected 3, got %d\n", count);
615 hr = IXmlReader_GetDepth(reader, &count);
617 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
618 ok(count == 1, "Expected 1, got %d\n", count);
621 IStream_Release(stream);
622 IXmlReader_Release(reader);
629 r = CoInitialize( NULL );
630 ok( r == S_OK, "failed to init com\n");
632 if (!init_pointers())
638 test_reader_create();
641 test_read_xmldeclaration();