xmllite/tests: Use common wine_dbgstr_guid implementation from test.h.
[wine/multimedia.git] / dlls / xmllite / tests / reader.c
blob1f3d30655a98e8433b776760a01fe7665a616acc
1 /*
2 * IXmlReader tests
4 * Copyright 2010, 2012-2013 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
21 #define COBJMACROS
22 #define CONST_VTABLE
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "initguid.h"
30 #include "ole2.h"
31 #include "xmllite.h"
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,
38 IMalloc *pMalloc,
39 LPCWSTR encoding,
40 BOOL hint,
41 LPCWSTR base_uri,
42 IXmlReaderInput **ppInput);
44 static WCHAR *a2w(const char *str)
46 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
47 WCHAR *ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
48 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
49 return ret;
52 static void free_str(WCHAR *str)
54 HeapFree(GetProcessHeap(), 0, str);
57 static const char xmldecl_full[] = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
59 static IStream *create_stream_on_data(const char *data, int size)
61 IStream *stream = NULL;
62 HGLOBAL hglobal;
63 void *ptr;
64 HRESULT hr;
66 hglobal = GlobalAlloc(GHND, size);
67 ptr = GlobalLock(hglobal);
69 memcpy(ptr, data, size);
71 hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
72 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
73 ok(stream != NULL, "Expected non-NULL stream\n");
75 GlobalUnlock(hglobal);
77 return stream;
80 static void ok_pos_(IXmlReader *reader, int line, int pos, int line_broken,
81 int pos_broken, BOOL todo, int _line_)
83 UINT l, p;
84 HRESULT hr;
85 BOOL broken_state;
87 hr = IXmlReader_GetLineNumber(reader, &l);
88 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
89 hr = IXmlReader_GetLinePosition(reader, &p);
90 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
92 if (line_broken == -1 && pos_broken == -1)
93 broken_state = FALSE;
94 else
95 broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
96 (pos_broken == -1 ? pos : pos_broken) == p);
98 if (todo)
99 todo_wine
100 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
101 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
102 else
104 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
105 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
108 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
110 typedef struct input_iids_t {
111 IID iids[10];
112 int count;
113 } input_iids_t;
115 static const IID *setinput_full[] = {
116 &IID_IXmlReaderInput,
117 &IID_IStream,
118 &IID_ISequentialStream,
119 NULL
122 /* this applies to early xmllite versions */
123 static const IID *setinput_full_old[] = {
124 &IID_IXmlReaderInput,
125 &IID_ISequentialStream,
126 &IID_IStream,
127 NULL
130 /* after ::SetInput(IXmlReaderInput*) */
131 static const IID *setinput_readerinput[] = {
132 &IID_IStream,
133 &IID_ISequentialStream,
134 NULL
137 static const IID *empty_seq[] = {
138 NULL
141 static input_iids_t input_iids;
143 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, BOOL todo, int line)
145 int i = 0, size = 0;
147 while (expected[i++]) size++;
149 if (todo) {
150 todo_wine
151 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
153 else
154 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
156 if (iids->count != size) return;
158 for (i = 0; i < size; i++) {
159 ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
160 (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
161 "Wrong IID(%d), got %s\n", i, wine_dbgstr_guid(&iids->iids[i]));
164 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
166 static const char *state_to_str(XmlReadState state)
168 static const char* state_names[] = {
169 "XmlReadState_Initial",
170 "XmlReadState_Interactive",
171 "XmlReadState_Error",
172 "XmlReadState_EndOfFile",
173 "XmlReadState_Closed"
176 static const char unknown[] = "unknown";
178 switch (state)
180 case XmlReadState_Initial:
181 case XmlReadState_Interactive:
182 case XmlReadState_Error:
183 case XmlReadState_EndOfFile:
184 case XmlReadState_Closed:
185 return state_names[state];
186 default:
187 return unknown;
191 static const char *type_to_str(XmlNodeType type)
193 static const char* type_names[] = {
194 "XmlNodeType_None",
195 "XmlNodeType_Element",
196 "XmlNodeType_Attribute",
197 "XmlNodeType_Text",
198 "XmlNodeType_CDATA",
199 "", "",
200 "XmlNodeType_ProcessingInstruction",
201 "XmlNodeType_Comment",
203 "XmlNodeType_DocumentType",
204 "", "",
205 "XmlNodeType_Whitespace",
207 "XmlNodeType_EndElement",
209 "XmlNodeType_XmlDeclaration"
212 static const char unknown[] = "unknown";
214 switch (type)
216 case XmlNodeType_None:
217 case XmlNodeType_Element:
218 case XmlNodeType_Attribute:
219 case XmlNodeType_Text:
220 case XmlNodeType_CDATA:
221 case XmlNodeType_ProcessingInstruction:
222 case XmlNodeType_Comment:
223 case XmlNodeType_DocumentType:
224 case XmlNodeType_Whitespace:
225 case XmlNodeType_EndElement:
226 case XmlNodeType_XmlDeclaration:
227 return type_names[type];
228 default:
229 return unknown;
233 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
234 XmlReadState exp_broken, BOOL todo, int line)
236 XmlReadState state;
237 HRESULT hr;
238 BOOL broken_state;
240 state = -1; /* invalid value */
241 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
242 ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
244 if (exp_broken == -1)
245 broken_state = FALSE;
246 else
247 broken_state = broken(exp_broken == state);
249 if (todo)
251 todo_wine
252 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
253 state_to_str(expected), state_to_str(state));
255 else
256 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
257 state_to_str(expected), state_to_str(state));
260 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
262 typedef struct _testinput
264 IUnknown IUnknown_iface;
265 LONG ref;
266 } testinput;
268 static inline testinput *impl_from_IUnknown(IUnknown *iface)
270 return CONTAINING_RECORD(iface, testinput, IUnknown_iface);
273 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
275 if (IsEqualGUID( riid, &IID_IUnknown ))
277 *ppvObj = iface;
278 IUnknown_AddRef(iface);
279 return S_OK;
282 input_iids.iids[input_iids.count++] = *riid;
284 *ppvObj = NULL;
286 return E_NOINTERFACE;
289 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
291 testinput *This = impl_from_IUnknown(iface);
292 return InterlockedIncrement(&This->ref);
295 static ULONG WINAPI testinput_Release(IUnknown *iface)
297 testinput *This = impl_from_IUnknown(iface);
298 LONG ref;
300 ref = InterlockedDecrement(&This->ref);
301 if (ref == 0)
303 HeapFree(GetProcessHeap(), 0, This);
306 return ref;
309 static const struct IUnknownVtbl testinput_vtbl =
311 testinput_QueryInterface,
312 testinput_AddRef,
313 testinput_Release
316 static HRESULT testinput_createinstance(void **ppObj)
318 testinput *input;
320 input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
321 if(!input) return E_OUTOFMEMORY;
323 input->IUnknown_iface.lpVtbl = &testinput_vtbl;
324 input->ref = 1;
326 *ppObj = &input->IUnknown_iface;
328 return S_OK;
331 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
333 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
335 *obj = iface;
336 return S_OK;
339 *obj = NULL;
340 return E_NOINTERFACE;
343 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
345 return 2;
348 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
350 return 1;
353 static int stream_readcall;
355 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
357 static const char xml[] = "<!-- comment -->";
359 if (stream_readcall++)
361 *pread = 0;
362 return E_PENDING;
365 *pread = sizeof(xml) / 2;
366 memcpy(pv, xml, *pread);
367 return S_OK;
370 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
372 ok(0, "unexpected call\n");
373 return E_NOTIMPL;
376 static const ISequentialStreamVtbl teststreamvtbl =
378 teststream_QueryInterface,
379 teststream_AddRef,
380 teststream_Release,
381 teststream_Read,
382 teststream_Write
385 static BOOL init_pointers(void)
387 /* don't free module here, it's to be unloaded on exit */
388 HMODULE mod = LoadLibraryA("xmllite.dll");
390 if (!mod)
392 win_skip("xmllite library not available\n");
393 return FALSE;
396 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
397 MAKEFUNC(CreateXmlReader);
398 MAKEFUNC(CreateXmlReaderInputWithEncodingName);
399 #undef MAKEFUNC
401 return TRUE;
404 static void test_reader_create(void)
406 HRESULT hr;
407 IXmlReader *reader;
408 IUnknown *input;
409 DtdProcessing dtd;
410 XmlNodeType nodetype;
412 /* crashes native */
413 if (0)
415 pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
416 pCreateXmlReader(NULL, (void**)&reader, NULL);
419 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
420 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
422 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
424 nodetype = XmlNodeType_Element;
425 hr = IXmlReader_GetNodeType(reader, &nodetype);
426 ok(hr == S_FALSE, "got %08x\n", hr);
427 ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
429 dtd = 2;
430 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
431 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
432 ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
434 dtd = 2;
435 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
436 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
438 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
439 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
441 /* Null input pointer, releases previous input */
442 hr = IXmlReader_SetInput(reader, NULL);
443 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
445 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
447 /* test input interface selection sequence */
448 hr = testinput_createinstance((void**)&input);
449 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
451 if (hr == S_OK)
453 input_iids.count = 0;
454 hr = IXmlReader_SetInput(reader, input);
455 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
456 ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
457 IUnknown_Release(input);
459 IXmlReader_Release(reader);
462 static void test_readerinput(void)
464 IXmlReaderInput *reader_input;
465 IXmlReader *reader, *reader2;
466 IUnknown *obj, *input;
467 IStream *stream, *stream2;
468 XmlNodeType nodetype;
469 HRESULT hr;
470 LONG ref;
472 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
473 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
474 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
475 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
477 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
478 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
480 ref = IStream_AddRef(stream);
481 ok(ref == 2, "Expected 2, got %d\n", ref);
482 IStream_Release(stream);
483 hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
484 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
486 hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
487 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
489 hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
490 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
492 /* IXmlReaderInput grabs a stream reference */
493 ref = IStream_AddRef(stream);
494 ok(ref == 3, "Expected 3, got %d\n", ref);
495 IStream_Release(stream);
497 /* try ::SetInput() with valid IXmlReaderInput */
498 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
499 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
501 ref = IUnknown_AddRef(reader_input);
502 ok(ref == 2, "Expected 2, got %d\n", ref);
503 IUnknown_Release(reader_input);
505 hr = IXmlReader_SetInput(reader, reader_input);
506 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
508 test_read_state(reader, XmlReadState_Initial, -1, FALSE);
510 nodetype = XmlNodeType_Element;
511 hr = IXmlReader_GetNodeType(reader, &nodetype);
512 ok(hr == S_OK, "got %08x\n", hr);
513 ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
515 /* IXmlReader grabs a IXmlReaderInput reference */
516 ref = IUnknown_AddRef(reader_input);
517 ok(ref == 3, "Expected 3, got %d\n", ref);
518 IUnknown_Release(reader_input);
520 ref = IStream_AddRef(stream);
521 ok(ref == 4, "Expected 4, got %d\n", ref);
522 IStream_Release(stream);
524 /* reset input and check state */
525 hr = IXmlReader_SetInput(reader, NULL);
526 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
528 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
530 IXmlReader_Release(reader);
532 ref = IStream_AddRef(stream);
533 ok(ref == 3, "Expected 3, got %d\n", ref);
534 IStream_Release(stream);
536 ref = IUnknown_AddRef(reader_input);
537 ok(ref == 2, "Expected 2, got %d\n", ref);
538 IUnknown_Release(reader_input);
540 /* IID_IXmlReaderInput */
541 /* it returns a kind of private undocumented vtable incompatible with IUnknown,
542 so it's not a COM interface actually.
543 Such query will be used only to check if input is really IXmlReaderInput */
544 obj = (IUnknown*)0xdeadbeef;
545 hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
546 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
547 ref = IUnknown_AddRef(reader_input);
548 ok(ref == 3, "Expected 3, got %d\n", ref);
549 IUnknown_Release(reader_input);
551 IUnknown_Release(reader_input);
552 IUnknown_Release(reader_input);
553 IStream_Release(stream);
555 /* test input interface selection sequence */
556 input = NULL;
557 hr = testinput_createinstance((void**)&input);
558 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
560 input_iids.count = 0;
561 ref = IUnknown_AddRef(input);
562 ok(ref == 2, "Expected 2, got %d\n", ref);
563 IUnknown_Release(input);
564 hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
565 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
566 ok_iids(&input_iids, empty_seq, NULL, FALSE);
567 /* IXmlReaderInput stores stream interface as IUnknown */
568 ref = IUnknown_AddRef(input);
569 ok(ref == 3, "Expected 3, got %d\n", ref);
570 IUnknown_Release(input);
572 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
573 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
575 input_iids.count = 0;
576 ref = IUnknown_AddRef(reader_input);
577 ok(ref == 2, "Expected 2, got %d\n", ref);
578 IUnknown_Release(reader_input);
579 ref = IUnknown_AddRef(input);
580 ok(ref == 3, "Expected 3, got %d\n", ref);
581 IUnknown_Release(input);
582 hr = IXmlReader_SetInput(reader, reader_input);
583 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
584 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
586 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
588 ref = IUnknown_AddRef(input);
589 ok(ref == 3, "Expected 3, got %d\n", ref);
590 IUnknown_Release(input);
592 ref = IUnknown_AddRef(reader_input);
593 ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
594 "Expected 3, got %d\n", ref);
595 IUnknown_Release(reader_input);
596 /* repeat another time, no check or caching here */
597 input_iids.count = 0;
598 hr = IXmlReader_SetInput(reader, reader_input);
599 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
600 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
602 /* another reader */
603 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
604 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
606 /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
607 ::SetInput() level, each time it's called */
608 input_iids.count = 0;
609 hr = IXmlReader_SetInput(reader2, reader_input);
610 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
611 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
613 IXmlReader_Release(reader2);
614 IXmlReader_Release(reader);
616 IUnknown_Release(reader_input);
617 IUnknown_Release(input);
620 static void test_reader_state(void)
622 IXmlReader *reader;
623 XmlNodeType nodetype;
624 HRESULT hr;
626 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
627 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
629 /* invalid arguments */
630 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
631 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
633 /* attempt to read on closed reader */
634 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
635 if (0)
637 /* newer versions crash here, probably cause no input was set */
638 hr = IXmlReader_Read(reader, &nodetype);
639 ok(hr == S_FALSE, "got %08x\n", hr);
641 IXmlReader_Release(reader);
644 static void test_read_xmldeclaration(void)
646 IXmlReader *reader;
647 IStream *stream;
648 HRESULT hr;
649 XmlNodeType type;
650 UINT count = 0;
651 const WCHAR *val;
653 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
654 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
656 /* position methods with Null args */
657 hr = IXmlReader_GetLineNumber(reader, NULL);
658 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
660 hr = IXmlReader_GetLinePosition(reader, NULL);
661 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
663 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
665 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
666 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
668 hr = IXmlReader_GetAttributeCount(reader, &count);
669 ok(hr == S_OK, "got %08x\n", hr);
670 ok(count == 0, "got %d\n", count);
672 /* try to move without attributes */
673 hr = IXmlReader_MoveToElement(reader);
674 ok(hr == S_FALSE, "got %08x\n", hr);
676 hr = IXmlReader_MoveToNextAttribute(reader);
677 ok(hr == S_FALSE, "got %08x\n", hr);
679 hr = IXmlReader_MoveToFirstAttribute(reader);
680 ok(hr == S_FALSE, "got %08x\n", hr);
682 ok_pos(reader, 0, 0, -1, -1, FALSE);
684 type = -1;
685 hr = IXmlReader_Read(reader, &type);
686 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
687 ok(type == XmlNodeType_XmlDeclaration,
688 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
689 /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
690 ok_pos(reader, 1, 3, -1, 55, TRUE);
691 test_read_state(reader, XmlReadState_Interactive, -1, FALSE);
693 hr = IXmlReader_GetValue(reader, &val, NULL);
694 ok(hr == S_OK, "got %08x\n", hr);
695 ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
697 /* check attributes */
698 hr = IXmlReader_MoveToNextAttribute(reader);
699 ok(hr == S_OK, "got %08x\n", hr);
701 type = XmlNodeType_None;
702 hr = IXmlReader_GetNodeType(reader, &type);
703 ok(hr == S_OK, "got %08x\n", hr);
704 ok(type == XmlNodeType_Attribute, "got %d\n", type);
706 ok_pos(reader, 1, 7, -1, 55, TRUE);
708 /* try to move from last attribute */
709 hr = IXmlReader_MoveToNextAttribute(reader);
710 ok(hr == S_OK, "got %08x\n", hr);
711 hr = IXmlReader_MoveToNextAttribute(reader);
712 ok(hr == S_OK, "got %08x\n", hr);
713 hr = IXmlReader_MoveToNextAttribute(reader);
714 ok(hr == S_FALSE, "got %08x\n", hr);
716 type = XmlNodeType_None;
717 hr = IXmlReader_GetNodeType(reader, &type);
718 ok(hr == S_OK, "got %08x\n", hr);
719 ok(type == XmlNodeType_Attribute, "got %d\n", type);
721 hr = IXmlReader_MoveToFirstAttribute(reader);
722 ok(hr == S_OK, "got %08x\n", hr);
723 ok_pos(reader, 1, 7, -1, 55, TRUE);
725 hr = IXmlReader_GetAttributeCount(reader, NULL);
726 ok(hr == E_INVALIDARG, "got %08x\n", hr);
728 hr = IXmlReader_GetAttributeCount(reader, &count);
729 ok(hr == S_OK, "got %08x\n", hr);
730 ok(count == 3, "Expected 3, got %d\n", count);
732 hr = IXmlReader_GetDepth(reader, &count);
733 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
734 ok(count == 1, "Expected 1, got %d\n", count);
736 hr = IXmlReader_MoveToElement(reader);
737 ok(hr == S_OK, "got %08x\n", hr);
739 type = XmlNodeType_None;
740 hr = IXmlReader_GetNodeType(reader, &type);
741 ok(hr == S_OK, "got %08x\n", hr);
742 ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type);
744 type = XmlNodeType_XmlDeclaration;
745 hr = IXmlReader_Read(reader, &type);
746 /* newer versions return syntax error here cause document is incomplete,
747 it makes more sense than invalid char error */
748 todo_wine {
749 ok(hr == WC_E_SYNTAX || broken(hr == WC_E_XMLCHARACTER), "got 0x%08x\n", hr);
750 ok(type == XmlNodeType_None, "got %d\n", type);
752 IStream_Release(stream);
753 IXmlReader_Release(reader);
756 struct test_entry {
757 const char *xml;
758 const char *name;
759 const char *value;
760 HRESULT hr;
761 HRESULT hr_broken; /* this is set to older version results */
762 BOOL todo;
765 static struct test_entry comment_tests[] = {
766 { "<!-- comment -->", "", " comment ", S_OK },
767 { "<!-- - comment-->", "", " - comment", S_OK },
768 { "<!-- -- comment-->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
769 { "<!-- -- comment--->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
770 { NULL }
773 static void test_read_comment(void)
775 struct test_entry *test = comment_tests;
776 IXmlReader *reader;
777 HRESULT hr;
779 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
780 ok(hr == S_OK, "S_OK, got %08x\n", hr);
782 while (test->xml)
784 XmlNodeType type;
785 IStream *stream;
787 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
788 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
789 ok(hr == S_OK, "got %08x\n", hr);
791 type = XmlNodeType_None;
792 hr = IXmlReader_Read(reader, &type);
793 if (test->hr_broken)
794 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
795 else
796 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
797 if (hr == S_OK)
799 const WCHAR *str;
800 WCHAR *str_exp;
801 UINT len;
803 ok(type == XmlNodeType_Comment, "got %d for %s\n", type, test->xml);
805 len = 1;
806 str = NULL;
807 hr = IXmlReader_GetLocalName(reader, &str, &len);
808 ok(hr == S_OK, "got 0x%08x\n", hr);
809 ok(len == strlen(test->name), "got %u\n", len);
810 str_exp = a2w(test->name);
811 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
812 free_str(str_exp);
814 len = 1;
815 str = NULL;
816 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
817 ok(hr == S_OK, "got 0x%08x\n", hr);
818 ok(len == strlen(test->name), "got %u\n", len);
819 str_exp = a2w(test->name);
820 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
821 free_str(str_exp);
823 /* value */
824 len = 1;
825 str = NULL;
826 hr = IXmlReader_GetValue(reader, &str, &len);
827 ok(hr == S_OK, "got 0x%08x\n", hr);
828 ok(len == strlen(test->value), "got %u\n", len);
829 str_exp = a2w(test->value);
830 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
831 free_str(str_exp);
834 IStream_Release(stream);
835 test++;
838 IXmlReader_Release(reader);
841 static struct test_entry pi_tests[] = {
842 { "<?pi?>", "pi", "", S_OK },
843 { "<?pi ?>", "pi", "", S_OK },
844 { "<?pi ?>", "pi", "", S_OK },
845 { "<?pi pi data?>", "pi", "pi data", S_OK },
846 { "<?pi pi data ?>", "pi", "pi data ", S_OK },
847 { "<?pi data ?>", "pi", "data ", S_OK },
848 { "<?pi:pi?>", NULL, NULL, NC_E_NAMECOLON, WC_E_NAMECHARACTER },
849 { "<?:pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
850 { "<?-pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
851 { "<?xml-stylesheet ?>", "xml-stylesheet", "", S_OK },
852 { NULL }
855 static void test_read_pi(void)
857 struct test_entry *test = pi_tests;
858 IXmlReader *reader;
859 HRESULT hr;
861 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
862 ok(hr == S_OK, "S_OK, got %08x\n", hr);
864 while (test->xml)
866 XmlNodeType type;
867 IStream *stream;
869 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
870 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
871 ok(hr == S_OK, "got %08x\n", hr);
873 type = XmlNodeType_None;
874 hr = IXmlReader_Read(reader, &type);
875 if (test->hr_broken)
876 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
877 else
878 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
879 if (hr == S_OK)
881 const WCHAR *str;
882 WCHAR *str_exp;
883 UINT len;
885 ok(type == XmlNodeType_ProcessingInstruction, "got %d for %s\n", type, test->xml);
887 len = 0;
888 str = NULL;
889 hr = IXmlReader_GetLocalName(reader, &str, &len);
890 ok(hr == S_OK, "got 0x%08x\n", hr);
891 ok(len == strlen(test->name), "got %u\n", len);
892 str_exp = a2w(test->name);
893 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
894 free_str(str_exp);
896 len = 0;
897 str = NULL;
898 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
899 ok(hr == S_OK, "got 0x%08x\n", hr);
900 ok(len == strlen(test->name), "got %u\n", len);
901 str_exp = a2w(test->name);
902 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
903 free_str(str_exp);
905 /* value */
906 len = !strlen(test->value);
907 str = NULL;
908 hr = IXmlReader_GetValue(reader, &str, &len);
909 ok(hr == S_OK, "got 0x%08x\n", hr);
910 ok(len == strlen(test->value), "got %u\n", len);
911 str_exp = a2w(test->value);
912 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
913 free_str(str_exp);
916 IStream_Release(stream);
917 test++;
920 IXmlReader_Release(reader);
923 struct nodes_test {
924 const char *xml;
925 XmlNodeType types[20];
928 static const char misc_test_xml[] =
929 "<!-- comment1 -->"
930 "<!-- comment2 -->"
931 "<?pi1 pi1body ?>"
932 "<!-- comment3 -->"
933 " \t \r \n"
934 "<!-- comment4 -->"
935 "<a>"
936 "\r\n\t"
937 "<b/>"
938 "text"
939 "<!-- comment -->"
940 "text2"
941 "<?pi pibody ?>"
942 "\r\n"
943 "</a>"
946 static struct nodes_test misc_test = {
947 misc_test_xml,
949 XmlNodeType_Comment,
950 XmlNodeType_Comment,
951 XmlNodeType_ProcessingInstruction,
952 XmlNodeType_Comment,
953 XmlNodeType_Whitespace,
954 XmlNodeType_Comment,
955 XmlNodeType_Element,
956 XmlNodeType_Whitespace,
957 XmlNodeType_Element,
958 XmlNodeType_Text,
959 XmlNodeType_Comment,
960 XmlNodeType_Text,
961 XmlNodeType_ProcessingInstruction,
962 XmlNodeType_Whitespace,
963 XmlNodeType_EndElement,
964 XmlNodeType_None
968 static void test_read_full(void)
970 struct nodes_test *test = &misc_test;
971 IXmlReader *reader;
972 XmlNodeType type;
973 IStream *stream;
974 HRESULT hr;
975 int i;
977 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
978 ok(hr == S_OK, "S_OK, got %08x\n", hr);
980 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
981 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
982 ok(hr == S_OK, "got %08x\n", hr);
984 i = 0;
985 type = XmlNodeType_None;
986 hr = IXmlReader_Read(reader, &type);
987 while (hr == S_OK)
989 ok(test->types[i] != XmlNodeType_None, "%d: unexpected end of test data\n", i);
990 if (test->types[i] == XmlNodeType_None) break;
991 ok(type == test->types[i], "%d: got wrong type %d, expected %d\n", i, type, test->types[i]);
992 if (type == XmlNodeType_Whitespace)
994 const WCHAR *ptr;
995 UINT len = 0;
997 hr = IXmlReader_GetValue(reader, &ptr, &len);
998 ok(hr == S_OK, "%d: GetValue failed 0x%08x\n", i, hr);
999 ok(len > 0, "%d: wrong value length %d\n", i, len);
1001 hr = IXmlReader_Read(reader, &type);
1002 i++;
1004 ok(test->types[i] == XmlNodeType_None, "incomplete sequence, got %d\n", test->types[i]);
1006 IStream_Release(stream);
1007 IXmlReader_Release(reader);
1010 static const char test_dtd[] =
1011 "<!DOCTYPE testdtd SYSTEM \"externalid uri\" >"
1012 "<!-- comment -->";
1014 static void test_read_dtd(void)
1016 static const WCHAR sysvalW[] = {'e','x','t','e','r','n','a','l','i','d',' ','u','r','i',0};
1017 static const WCHAR dtdnameW[] = {'t','e','s','t','d','t','d',0};
1018 static const WCHAR sysW[] = {'S','Y','S','T','E','M',0};
1019 IXmlReader *reader;
1020 const WCHAR *str;
1021 XmlNodeType type;
1022 IStream *stream;
1023 UINT len, count;
1024 HRESULT hr;
1026 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1027 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1029 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, DtdProcessing_Parse);
1030 ok(hr == S_OK, "got 0x%8x\n", hr);
1032 stream = create_stream_on_data(test_dtd, sizeof(test_dtd));
1033 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1034 ok(hr == S_OK, "got %08x\n", hr);
1036 type = XmlNodeType_None;
1037 hr = IXmlReader_Read(reader, &type);
1038 ok(hr == S_OK, "got 0x%8x\n", hr);
1039 ok(type == XmlNodeType_DocumentType, "got type %d\n", type);
1041 count = 0;
1042 hr = IXmlReader_GetAttributeCount(reader, &count);
1043 ok(hr == S_OK, "got %08x\n", hr);
1044 ok(count == 1, "got %d\n", count);
1046 hr = IXmlReader_MoveToFirstAttribute(reader);
1047 ok(hr == S_OK, "got %08x\n", hr);
1049 type = XmlNodeType_None;
1050 hr = IXmlReader_GetNodeType(reader, &type);
1051 ok(hr == S_OK, "got %08x\n", hr);
1052 ok(type == XmlNodeType_Attribute, "got %d\n", type);
1054 len = 0;
1055 str = NULL;
1056 hr = IXmlReader_GetLocalName(reader, &str, &len);
1057 ok(hr == S_OK, "got 0x%08x\n", hr);
1058 ok(len == lstrlenW(sysW), "got %u\n", len);
1059 ok(!lstrcmpW(str, sysW), "got %s\n", wine_dbgstr_w(str));
1061 len = 0;
1062 str = NULL;
1063 hr = IXmlReader_GetValue(reader, &str, &len);
1064 ok(hr == S_OK, "got 0x%08x\n", hr);
1065 ok(len == lstrlenW(sysvalW), "got %u\n", len);
1066 ok(!lstrcmpW(str, sysvalW), "got %s\n", wine_dbgstr_w(str));
1068 hr = IXmlReader_MoveToElement(reader);
1069 ok(hr == S_OK, "got 0x%08x\n", hr);
1071 len = 0;
1072 str = NULL;
1073 hr = IXmlReader_GetLocalName(reader, &str, &len);
1074 ok(hr == S_OK, "got 0x%08x\n", hr);
1075 todo_wine {
1076 ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1077 ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1079 len = 0;
1080 str = NULL;
1081 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1082 ok(hr == S_OK, "got 0x%08x\n", hr);
1083 ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1084 ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1086 type = XmlNodeType_None;
1087 hr = IXmlReader_Read(reader, &type);
1088 ok(hr == S_OK, "got 0x%8x\n", hr);
1089 ok(type == XmlNodeType_Comment, "got type %d\n", type);
1091 IStream_Release(stream);
1092 IXmlReader_Release(reader);
1095 static struct test_entry element_tests[] = {
1096 { "<a/>", "a", "", S_OK },
1097 { "<a />", "a", "", S_OK },
1098 { "<a:b/>", "a:b", "", NC_E_UNDECLAREDPREFIX },
1099 { "<:a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1100 { "< a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1101 { "<a>", "a", "", S_OK },
1102 { "<a >", "a", "", S_OK },
1103 { "<a \r \t\n>", "a", "", S_OK },
1104 { "</a>", NULL, NULL, NC_E_QNAMECHARACTER },
1105 { NULL }
1108 static void test_read_element(void)
1110 struct test_entry *test = element_tests;
1111 static const char stag[] = "<a><b></b></a>";
1112 static const char mismatch[] = "<a></b>";
1113 IXmlReader *reader;
1114 XmlNodeType type;
1115 IStream *stream;
1116 UINT depth;
1117 HRESULT hr;
1119 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1120 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1122 while (test->xml)
1124 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1125 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1126 ok(hr == S_OK, "got %08x\n", hr);
1128 type = XmlNodeType_None;
1129 hr = IXmlReader_Read(reader, &type);
1130 if (test->hr_broken)
1131 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1132 else
1133 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1134 if (hr == S_OK)
1136 const WCHAR *str;
1137 WCHAR *str_exp;
1138 UINT len;
1140 ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
1142 len = 0;
1143 str = NULL;
1144 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1145 ok(hr == S_OK, "got 0x%08x\n", hr);
1146 ok(len == strlen(test->name), "got %u\n", len);
1147 str_exp = a2w(test->name);
1148 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1149 free_str(str_exp);
1151 /* value */
1152 len = 1;
1153 str = NULL;
1154 hr = IXmlReader_GetValue(reader, &str, &len);
1155 ok(hr == S_OK, "got 0x%08x\n", hr);
1156 ok(len == 0, "got %u\n", len);
1157 ok(*str == 0, "got %s\n", wine_dbgstr_w(str));
1160 IStream_Release(stream);
1161 test++;
1164 /* test reader depth increment */
1165 stream = create_stream_on_data(stag, sizeof(stag));
1166 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1167 ok(hr == S_OK, "got %08x\n", hr);
1169 depth = 1;
1170 hr = IXmlReader_GetDepth(reader, &depth);
1171 ok(hr == S_OK, "got %08x\n", hr);
1172 ok(depth == 0, "got %d\n", depth);
1174 type = XmlNodeType_None;
1175 hr = IXmlReader_Read(reader, &type);
1176 ok(hr == S_OK, "got %08x\n", hr);
1177 ok(type == XmlNodeType_Element, "got %d\n", type);
1179 depth = 1;
1180 hr = IXmlReader_GetDepth(reader, &depth);
1181 ok(hr == S_OK, "got %08x\n", hr);
1182 ok(depth == 0, "got %d\n", depth);
1184 type = XmlNodeType_None;
1185 hr = IXmlReader_Read(reader, &type);
1186 ok(hr == S_OK, "got %08x\n", hr);
1187 ok(type == XmlNodeType_Element, "got %d\n", type);
1189 depth = 0;
1190 hr = IXmlReader_GetDepth(reader, &depth);
1191 ok(hr == S_OK, "got %08x\n", hr);
1192 ok(depth == 1, "got %d\n", depth);
1194 /* read end tag for inner element */
1195 type = XmlNodeType_None;
1196 hr = IXmlReader_Read(reader, &type);
1197 ok(hr == S_OK, "got %08x\n", hr);
1198 ok(type == XmlNodeType_EndElement, "got %d\n", type);
1200 depth = 0;
1201 hr = IXmlReader_GetDepth(reader, &depth);
1202 ok(hr == S_OK, "got %08x\n", hr);
1203 todo_wine
1204 ok(depth == 2, "got %d\n", depth);
1206 /* read end tag for container element */
1207 type = XmlNodeType_None;
1208 hr = IXmlReader_Read(reader, &type);
1209 ok(hr == S_OK, "got %08x\n", hr);
1210 ok(type == XmlNodeType_EndElement, "got %d\n", type);
1212 depth = 0;
1213 hr = IXmlReader_GetDepth(reader, &depth);
1214 ok(hr == S_OK, "got %08x\n", hr);
1215 ok(depth == 1, "got %d\n", depth);
1217 IStream_Release(stream);
1219 /* start/end tag mismatch */
1220 stream = create_stream_on_data(mismatch, sizeof(mismatch));
1221 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1222 ok(hr == S_OK, "got %08x\n", hr);
1224 type = XmlNodeType_None;
1225 hr = IXmlReader_Read(reader, &type);
1226 ok(hr == S_OK, "got %08x\n", hr);
1227 ok(type == XmlNodeType_Element, "got %d\n", type);
1229 type = XmlNodeType_Element;
1230 hr = IXmlReader_Read(reader, &type);
1231 ok(hr == WC_E_ELEMENTMATCH, "got %08x\n", hr);
1232 todo_wine
1233 ok(type == XmlNodeType_None, "got %d\n", type);
1235 IStream_Release(stream);
1237 IXmlReader_Release(reader);
1240 static ISequentialStream teststream = { &teststreamvtbl };
1242 static void test_read_pending(void)
1244 IXmlReader *reader;
1245 const WCHAR *value;
1246 XmlNodeType type;
1247 HRESULT hr;
1248 int c;
1250 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1251 ok(hr == S_OK, "S_OK, got 0x%08x\n", hr);
1253 hr = IXmlReader_SetInput(reader, (IUnknown*)&teststream);
1254 ok(hr == S_OK, "got 0x%08x\n", hr);
1256 /* first read call returns incomplete node, second attempt fails with E_PENDING */
1257 stream_readcall = 0;
1258 type = XmlNodeType_Element;
1259 hr = IXmlReader_Read(reader, &type);
1260 ok(hr == S_OK || broken(hr == E_PENDING), "got 0x%08x\n", hr);
1261 /* newer versions are happy when it's enough data to detect node type,
1262 older versions keep reading until it fails to read more */
1263 ok(stream_readcall == 1 || broken(stream_readcall > 1), "got %d\n", stream_readcall);
1264 ok(type == XmlNodeType_Comment || broken(type == XmlNodeType_None), "got %d\n", type);
1266 /* newer versions' GetValue() makes an attempt to read more */
1267 c = stream_readcall;
1268 value = (void*)0xdeadbeef;
1269 hr = IXmlReader_GetValue(reader, &value, NULL);
1270 ok(hr == E_PENDING, "got 0x%08x\n", hr);
1271 ok(value == NULL || broken(value == (void*)0xdeadbeef) /* Win8 sets it to NULL */, "got %p\n", value);
1272 ok(c < stream_readcall || broken(c == stream_readcall), "got %d, expected %d\n", stream_readcall, c+1);
1274 IXmlReader_Release(reader);
1277 static void test_readvaluechunk(void)
1279 static const char testA[] = "<!-- comment1 -->";
1280 IXmlReader *reader;
1281 XmlNodeType type;
1282 IStream *stream;
1283 const WCHAR *value;
1284 WCHAR b;
1285 HRESULT hr;
1286 UINT c;
1288 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1289 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1291 stream = create_stream_on_data(testA, sizeof(testA));
1292 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1293 ok(hr == S_OK, "got %08x\n", hr);
1295 hr = IXmlReader_Read(reader, &type);
1296 ok(hr == S_OK, "got %08x\n", hr);
1298 c = 0;
1299 b = 0;
1300 hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1301 ok(hr == S_OK, "got %08x\n", hr);
1302 ok(c == 1, "got %u\n", c);
1303 ok(b == ' ', "got %x\n", b);
1305 /* portion read as chunk is skipped from resulting node value */
1306 value = NULL;
1307 hr = IXmlReader_GetValue(reader, &value, NULL);
1308 ok(hr == S_OK, "got %08x\n", hr);
1309 ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1311 /* once value is returned/allocated it's not possible to read by chunk */
1312 c = 0;
1313 b = 0;
1314 hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1315 ok(hr == S_FALSE, "got %08x\n", hr);
1316 ok(c == 0, "got %u\n", c);
1317 ok(b == 0, "got %x\n", b);
1319 value = NULL;
1320 hr = IXmlReader_GetValue(reader, &value, NULL);
1321 ok(hr == S_OK, "got %08x\n", hr);
1322 ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1324 IXmlReader_Release(reader);
1327 static struct test_entry cdata_tests[] = {
1328 { "<a><![CDATA[ ]]data ]]></a>", "", " ]]data ", S_OK },
1329 { "<a><![CDATA[<![CDATA[ data ]]]]></a>", "", "<![CDATA[ data ]]", S_OK },
1330 { "<a><![CDATA[\n \r\n \n\n ]]></a>", "", "\n \n \n\n ", S_OK, S_OK, TRUE },
1331 { "<a><![CDATA[\r \r\r\n \n\n ]]></a>", "", "\n \n\n \n\n ", S_OK, S_OK, TRUE },
1332 { "<a><![CDATA[\r\r \n\r \r \n\n ]]></a>", "", "\n\n \n\n \n \n\n ", S_OK },
1333 { NULL }
1336 static void test_read_cdata(void)
1338 struct test_entry *test = cdata_tests;
1339 IXmlReader *reader;
1340 HRESULT hr;
1342 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1343 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1345 while (test->xml)
1347 XmlNodeType type;
1348 IStream *stream;
1350 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1351 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1352 ok(hr == S_OK, "got %08x\n", hr);
1354 type = XmlNodeType_None;
1355 hr = IXmlReader_Read(reader, &type);
1357 /* read one more to get to CDATA */
1358 if (type == XmlNodeType_Element)
1360 type = XmlNodeType_None;
1361 hr = IXmlReader_Read(reader, &type);
1364 if (test->hr_broken)
1365 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1366 else
1367 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1368 if (hr == S_OK)
1370 const WCHAR *str;
1371 WCHAR *str_exp;
1372 UINT len;
1374 ok(type == XmlNodeType_CDATA, "got %d for %s\n", type, test->xml);
1376 str_exp = a2w(test->name);
1378 len = 1;
1379 str = NULL;
1380 hr = IXmlReader_GetLocalName(reader, &str, &len);
1381 ok(hr == S_OK, "got 0x%08x\n", hr);
1382 ok(len == strlen(test->name), "got %u\n", len);
1383 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1385 str = NULL;
1386 hr = IXmlReader_GetLocalName(reader, &str, NULL);
1387 ok(hr == S_OK, "got 0x%08x\n", hr);
1388 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1390 free_str(str_exp);
1392 len = 1;
1393 str = NULL;
1394 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1395 ok(hr == S_OK, "got 0x%08x\n", hr);
1396 ok(len == strlen(test->name), "got %u\n", len);
1397 str_exp = a2w(test->name);
1398 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1399 free_str(str_exp);
1401 /* value */
1402 len = 1;
1403 str = NULL;
1404 hr = IXmlReader_GetValue(reader, &str, &len);
1405 ok(hr == S_OK, "got 0x%08x\n", hr);
1407 str_exp = a2w(test->value);
1408 if (test->todo)
1410 todo_wine {
1411 ok(len == strlen(test->value), "got %u\n", len);
1412 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1415 else
1417 ok(len == strlen(test->value), "got %u\n", len);
1418 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1420 free_str(str_exp);
1423 IStream_Release(stream);
1424 test++;
1427 IXmlReader_Release(reader);
1430 static struct test_entry text_tests[] = {
1431 { "<a>simple text</a>", "", "simple text", S_OK },
1432 { "<a>text ]]> text</a>", "", "", WC_E_CDSECTEND },
1433 { NULL }
1436 static void test_read_text(void)
1438 struct test_entry *test = text_tests;
1439 IXmlReader *reader;
1440 HRESULT hr;
1442 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1443 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1445 while (test->xml)
1447 XmlNodeType type;
1448 IStream *stream;
1450 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1451 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1452 ok(hr == S_OK, "got %08x\n", hr);
1454 type = XmlNodeType_None;
1455 hr = IXmlReader_Read(reader, &type);
1457 /* read one more to get to CDATA */
1458 if (type == XmlNodeType_Element)
1460 type = XmlNodeType_None;
1461 hr = IXmlReader_Read(reader, &type);
1464 if (test->hr_broken)
1465 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1466 else
1467 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1468 if (hr == S_OK)
1470 const WCHAR *str;
1471 WCHAR *str_exp;
1472 UINT len;
1474 ok(type == XmlNodeType_Text, "got %d for %s\n", type, test->xml);
1476 str_exp = a2w(test->name);
1478 len = 1;
1479 str = NULL;
1480 hr = IXmlReader_GetLocalName(reader, &str, &len);
1481 ok(hr == S_OK, "got 0x%08x\n", hr);
1482 ok(len == strlen(test->name), "got %u\n", len);
1483 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1485 str = NULL;
1486 hr = IXmlReader_GetLocalName(reader, &str, NULL);
1487 ok(hr == S_OK, "got 0x%08x\n", hr);
1488 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1490 free_str(str_exp);
1492 len = 1;
1493 str = NULL;
1494 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1495 ok(hr == S_OK, "got 0x%08x\n", hr);
1496 ok(len == strlen(test->name), "got %u\n", len);
1497 str_exp = a2w(test->name);
1498 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1499 free_str(str_exp);
1501 /* value */
1502 len = 1;
1503 str = NULL;
1504 hr = IXmlReader_GetValue(reader, &str, &len);
1505 ok(hr == S_OK, "got 0x%08x\n", hr);
1507 str_exp = a2w(test->value);
1508 if (test->todo)
1510 todo_wine {
1511 ok(len == strlen(test->value), "got %u\n", len);
1512 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1515 else
1517 ok(len == strlen(test->value), "got %u\n", len);
1518 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1520 free_str(str_exp);
1523 IStream_Release(stream);
1524 test++;
1527 IXmlReader_Release(reader);
1530 struct test_entry_empty {
1531 const char *xml;
1532 BOOL empty;
1535 static struct test_entry_empty empty_element_tests[] = {
1536 { "<a></a>", FALSE },
1537 { "<a/>", TRUE },
1538 { NULL }
1541 static void test_isemptyelement(void)
1543 struct test_entry_empty *test = empty_element_tests;
1544 IXmlReader *reader;
1545 HRESULT hr;
1547 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1548 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1550 while (test->xml)
1552 XmlNodeType type;
1553 IStream *stream;
1554 BOOL ret;
1556 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1557 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1558 ok(hr == S_OK, "got %08x\n", hr);
1560 type = XmlNodeType_None;
1561 hr = IXmlReader_Read(reader, &type);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1563 ok(type == XmlNodeType_Element, "got %d\n", type);
1565 ret = IXmlReader_IsEmptyElement(reader);
1566 ok(ret == test->empty, "got %d, expected %d. xml=%s\n", ret, test->empty, test->xml);
1568 IStream_Release(stream);
1569 test++;
1572 IXmlReader_Release(reader);
1575 static struct test_entry attributes_tests[] = {
1576 { "<a attr1=\"attrvalue\"/>", "attr1", "attrvalue", S_OK },
1577 { "<a attr1=\"a\'\'ttrvalue\"/>", "attr1", "a\'\'ttrvalue", S_OK },
1578 { "<a attr1=\'a\"ttrvalue\'/>", "attr1", "a\"ttrvalue", S_OK },
1579 { "<a attr1=\' \'/>", "attr1", " ", S_OK },
1580 { "<a attr1=\" \"/>", "attr1", " ", S_OK },
1581 { "<a attr1=\"\r\n \r \n \t\n\r\"/>", "attr1", " ", S_OK },
1582 { "<a attr1=\" val \"/>", "attr1", " val ", S_OK },
1583 { "<a attr1=\"\r\n\tval\n\"/>", "attr1", " val ", S_OK },
1584 { "<a attr1=\"val&#32;\"/>", "attr1", "val ", S_OK },
1585 { "<a attr1=\"val&#x20;\"/>", "attr1", "val ", S_OK },
1586 { "<a attr1=\"&lt;&gt;&amp;&apos;&quot;\"/>", "attr1", "<>&\'\"", S_OK },
1587 { "<a attr1=\"&entname;\"/>", NULL, NULL, WC_E_UNDECLAREDENTITY },
1588 { "<a attr1=\"val&#xfffe;\"/>", NULL, NULL, WC_E_XMLCHARACTER },
1589 { "<a attr1=\"val &#a;\"/>", NULL, NULL, WC_E_DIGIT, WC_E_SEMICOLON },
1590 { "<a attr1=\"val &#12a;\"/>", NULL, NULL, WC_E_SEMICOLON },
1591 { "<a attr1=\"val &#x12g;\"/>", NULL, NULL, WC_E_SEMICOLON },
1592 { "<a attr1=\"val &#xg;\"/>", NULL, NULL, WC_E_HEXDIGIT, WC_E_SEMICOLON },
1593 { "<a attr1=attrvalue/>", NULL, NULL, WC_E_QUOTE },
1594 { "<a attr1=\"attr<value\"/>", NULL, NULL, WC_E_LESSTHAN },
1595 { "<a attr1=\"&entname\"/>", NULL, NULL, WC_E_SEMICOLON },
1596 { NULL }
1599 static void test_read_attribute(void)
1601 struct test_entry *test = attributes_tests;
1602 IXmlReader *reader;
1603 HRESULT hr;
1605 hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1606 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1608 while (test->xml)
1610 XmlNodeType type;
1611 IStream *stream;
1613 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1614 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1615 ok(hr == S_OK, "got %08x\n", hr);
1617 type = XmlNodeType_None;
1618 hr = IXmlReader_Read(reader, &type);
1620 if (test->hr_broken)
1621 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1622 else
1623 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1624 if (hr == S_OK)
1626 const WCHAR *str;
1627 WCHAR *str_exp;
1628 UINT len;
1630 ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
1632 hr = IXmlReader_MoveToFirstAttribute(reader);
1633 ok(hr == S_OK, "got 0x%08x\n", hr);
1635 len = 1;
1636 str = NULL;
1637 hr = IXmlReader_GetLocalName(reader, &str, &len);
1638 ok(hr == S_OK, "got 0x%08x\n", hr);
1639 ok(len == strlen(test->name), "got %u\n", len);
1640 str_exp = a2w(test->name);
1641 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1642 free_str(str_exp);
1644 len = 1;
1645 str = NULL;
1646 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1647 ok(hr == S_OK, "got 0x%08x\n", hr);
1648 todo_wine {
1649 ok(len == strlen(test->name), "got %u\n", len);
1650 str_exp = a2w(test->name);
1651 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1652 free_str(str_exp);
1654 /* value */
1655 len = 1;
1656 str = NULL;
1657 hr = IXmlReader_GetValue(reader, &str, &len);
1658 ok(hr == S_OK, "got 0x%08x\n", hr);
1659 ok(len == strlen(test->value), "got %u\n", len);
1660 str_exp = a2w(test->value);
1661 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1662 free_str(str_exp);
1665 IStream_Release(stream);
1666 test++;
1669 IXmlReader_Release(reader);
1672 START_TEST(reader)
1674 HRESULT r;
1676 r = CoInitialize( NULL );
1677 ok( r == S_OK, "failed to init com\n");
1679 if (!init_pointers())
1681 CoUninitialize();
1682 return;
1685 test_reader_create();
1686 test_readerinput();
1687 test_reader_state();
1688 test_read_attribute();
1689 test_read_cdata();
1690 test_read_comment();
1691 test_read_pi();
1692 test_read_dtd();
1693 test_read_element();
1694 test_isemptyelement();
1695 test_read_text();
1696 test_read_full();
1697 test_read_pending();
1698 test_readvaluechunk();
1699 test_read_xmldeclaration();
1701 CoUninitialize();