Release 1.5.29.
[wine] / dlls / xmllite / tests / reader.c
1 /*
2  * IXmlReader tests
3  *
4  * Copyright 2010, 2012-2013 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 #define CONST_VTABLE
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
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"
33
34 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
35
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);
43 static const char *debugstr_guid(REFIID riid)
44 {
45     static char buf[50];
46
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]);
51
52     return buf;
53 }
54
55 static WCHAR *a2w(const char *str)
56 {
57     int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
58     WCHAR *ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
59     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
60     return ret;
61 }
62
63 static void free_str(WCHAR *str)
64 {
65     HeapFree(GetProcessHeap(), 0, str);
66 }
67
68 static const char xmldecl_full[] = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
69
70 static IStream *create_stream_on_data(const char *data, int size)
71 {
72     IStream *stream = NULL;
73     HGLOBAL hglobal;
74     void *ptr;
75     HRESULT hr;
76
77     hglobal = GlobalAlloc(GHND, size);
78     ptr = GlobalLock(hglobal);
79
80     memcpy(ptr, data, size);
81
82     hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
83     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
84     ok(stream != NULL, "Expected non-NULL stream\n");
85
86     GlobalUnlock(hglobal);
87
88     return stream;
89 }
90
91 static void ok_pos_(IXmlReader *reader, int line, int pos, int line_broken,
92                                            int pos_broken, int todo, int _line_)
93 {
94     UINT l, p;
95     HRESULT hr;
96     int broken_state;
97
98     hr = IXmlReader_GetLineNumber(reader, &l);
99     ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
100     hr = IXmlReader_GetLinePosition(reader, &p);
101     ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
102
103     if (line_broken == -1 && pos_broken == -1)
104         broken_state = 0;
105     else
106         broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
107                               (pos_broken == -1 ? pos : pos_broken) == p);
108
109     if (todo)
110         todo_wine
111         ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
112                             "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
113     else
114     {
115         ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
116                             "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
117     }
118 }
119 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
120
121 typedef struct input_iids_t {
122     IID iids[10];
123     int count;
124 } input_iids_t;
125
126 static const IID *setinput_full[] = {
127     &IID_IXmlReaderInput,
128     &IID_IStream,
129     &IID_ISequentialStream,
130     NULL
131 };
132
133 /* this applies to early xmllite versions */
134 static const IID *setinput_full_old[] = {
135     &IID_IXmlReaderInput,
136     &IID_ISequentialStream,
137     &IID_IStream,
138     NULL
139 };
140
141 /* after ::SetInput(IXmlReaderInput*) */
142 static const IID *setinput_readerinput[] = {
143     &IID_IStream,
144     &IID_ISequentialStream,
145     NULL
146 };
147
148 static const IID *empty_seq[] = {
149     NULL
150 };
151
152 static input_iids_t input_iids;
153
154 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line)
155 {
156     int i = 0, size = 0;
157
158     while (expected[i++]) size++;
159
160     if (todo) {
161         todo_wine
162             ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
163     }
164     else
165        ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
166
167     if (iids->count != size) return;
168
169     for (i = 0; i < size; i++) {
170         ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
171             (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
172             "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
173     }
174 }
175 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
176
177 static const char *state_to_str(XmlReadState state)
178 {
179     static const char* state_names[] = {
180         "XmlReadState_Initial",
181         "XmlReadState_Interactive",
182         "XmlReadState_Error",
183         "XmlReadState_EndOfFile",
184         "XmlReadState_Closed"
185     };
186
187     static const char unknown[] = "unknown";
188
189     switch (state)
190     {
191     case XmlReadState_Initial:
192     case XmlReadState_Interactive:
193     case XmlReadState_Error:
194     case XmlReadState_EndOfFile:
195     case XmlReadState_Closed:
196         return state_names[state];
197     default:
198         return unknown;
199     }
200 }
201
202 static const char *type_to_str(XmlNodeType type)
203 {
204     static const char* type_names[] = {
205         "XmlNodeType_None",
206         "XmlNodeType_Element",
207         "XmlNodeType_Attribute",
208         "XmlNodeType_Text",
209         "XmlNodeType_CDATA",
210         "", "",
211         "XmlNodeType_ProcessingInstruction",
212         "XmlNodeType_Comment",
213         "",
214         "XmlNodeType_DocumentType",
215         "", "",
216         "XmlNodeType_Whitespace",
217         "",
218         "XmlNodeType_EndElement",
219         "",
220         "XmlNodeType_XmlDeclaration"
221     };
222
223     static const char unknown[] = "unknown";
224
225     switch (type)
226     {
227     case XmlNodeType_None:
228     case XmlNodeType_Element:
229     case XmlNodeType_Attribute:
230     case XmlNodeType_Text:
231     case XmlNodeType_CDATA:
232     case XmlNodeType_ProcessingInstruction:
233     case XmlNodeType_Comment:
234     case XmlNodeType_DocumentType:
235     case XmlNodeType_Whitespace:
236     case XmlNodeType_EndElement:
237     case XmlNodeType_XmlDeclaration:
238         return type_names[type];
239     default:
240         return unknown;
241     }
242 }
243
244 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
245                                     XmlReadState exp_broken, int todo, int line)
246 {
247     XmlReadState state;
248     HRESULT hr;
249     int broken_state;
250
251     state = -1; /* invalid value */
252     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
253     ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
254
255     if (exp_broken == -1)
256         broken_state = 0;
257     else
258         broken_state = broken(exp_broken == state);
259
260     if (todo)
261     {
262     todo_wine
263         ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
264                                    state_to_str(expected), state_to_str(state));
265     }
266     else
267         ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
268                                    state_to_str(expected), state_to_str(state));
269 }
270
271 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
272
273 typedef struct _testinput
274 {
275     IUnknown IUnknown_iface;
276     LONG ref;
277 } testinput;
278
279 static inline testinput *impl_from_IUnknown(IUnknown *iface)
280 {
281     return CONTAINING_RECORD(iface, testinput, IUnknown_iface);
282 }
283
284 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
285 {
286     if (IsEqualGUID( riid, &IID_IUnknown ))
287     {
288         *ppvObj = iface;
289         IUnknown_AddRef(iface);
290         return S_OK;
291     }
292
293     input_iids.iids[input_iids.count++] = *riid;
294
295     *ppvObj = NULL;
296
297     return E_NOINTERFACE;
298 }
299
300 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
301 {
302     testinput *This = impl_from_IUnknown(iface);
303     return InterlockedIncrement(&This->ref);
304 }
305
306 static ULONG WINAPI testinput_Release(IUnknown *iface)
307 {
308     testinput *This = impl_from_IUnknown(iface);
309     LONG ref;
310
311     ref = InterlockedDecrement(&This->ref);
312     if (ref == 0)
313     {
314         HeapFree(GetProcessHeap(), 0, This);
315     }
316
317     return ref;
318 }
319
320 static const struct IUnknownVtbl testinput_vtbl =
321 {
322     testinput_QueryInterface,
323     testinput_AddRef,
324     testinput_Release
325 };
326
327 static HRESULT testinput_createinstance(void **ppObj)
328 {
329     testinput *input;
330
331     input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
332     if(!input) return E_OUTOFMEMORY;
333
334     input->IUnknown_iface.lpVtbl = &testinput_vtbl;
335     input->ref = 1;
336
337     *ppObj = &input->IUnknown_iface;
338
339     return S_OK;
340 }
341
342 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
343 {
344     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
345     {
346         *obj = iface;
347         return S_OK;
348     }
349
350     *obj = NULL;
351     return E_NOINTERFACE;
352 }
353
354 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
355 {
356     return 2;
357 }
358
359 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
360 {
361     return 1;
362 }
363
364 static int stream_readcall;
365
366 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
367 {
368     static const char xml[] = "<!-- comment -->";
369
370     if (stream_readcall++)
371     {
372         *pread = 0;
373         return E_PENDING;
374     }
375
376     *pread = sizeof(xml) / 2;
377     memcpy(pv, xml, *pread);
378     return S_OK;
379 }
380
381 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
382 {
383     ok(0, "unexpected call\n");
384     return E_NOTIMPL;
385 }
386
387 static const ISequentialStreamVtbl teststreamvtbl =
388 {
389     teststream_QueryInterface,
390     teststream_AddRef,
391     teststream_Release,
392     teststream_Read,
393     teststream_Write
394 };
395
396 static BOOL init_pointers(void)
397 {
398     /* don't free module here, it's to be unloaded on exit */
399     HMODULE mod = LoadLibraryA("xmllite.dll");
400
401     if (!mod)
402     {
403         win_skip("xmllite library not available\n");
404         return FALSE;
405     }
406
407 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
408     MAKEFUNC(CreateXmlReader);
409     MAKEFUNC(CreateXmlReaderInputWithEncodingName);
410 #undef MAKEFUNC
411
412     return TRUE;
413 }
414
415 static void test_reader_create(void)
416 {
417     HRESULT hr;
418     IXmlReader *reader;
419     IUnknown *input;
420     DtdProcessing dtd;
421     XmlNodeType nodetype;
422
423     /* crashes native */
424     if (0)
425     {
426         pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
427         pCreateXmlReader(NULL, (void**)&reader, NULL);
428     }
429
430     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
431     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
432
433     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
434
435     nodetype = XmlNodeType_Element;
436     hr = IXmlReader_GetNodeType(reader, &nodetype);
437     ok(hr == S_FALSE, "got %08x\n", hr);
438     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
439
440     dtd = 2;
441     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
442     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
443     ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
444
445     dtd = 2;
446     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
447     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
448
449     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
450     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
451
452     /* Null input pointer, releases previous input */
453     hr = IXmlReader_SetInput(reader, NULL);
454     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
455
456     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
457
458     /* test input interface selection sequence */
459     hr = testinput_createinstance((void**)&input);
460     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
461
462     if (hr == S_OK)
463     {
464         input_iids.count = 0;
465         hr = IXmlReader_SetInput(reader, input);
466         ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
467         ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
468         IUnknown_Release(input);
469     }
470     IXmlReader_Release(reader);
471 }
472
473 static void test_readerinput(void)
474 {
475     IXmlReaderInput *reader_input;
476     IXmlReader *reader, *reader2;
477     IUnknown *obj, *input;
478     IStream *stream, *stream2;
479     XmlNodeType nodetype;
480     HRESULT hr;
481     LONG ref;
482
483     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
484     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
485     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
486     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
487
488     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
489     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
490
491     ref = IStream_AddRef(stream);
492     ok(ref == 2, "Expected 2, got %d\n", ref);
493     IStream_Release(stream);
494     hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
495     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
496
497     hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
498     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
499
500     hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
501     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
502
503     /* IXmlReaderInput grabs a stream reference */
504     ref = IStream_AddRef(stream);
505     ok(ref == 3, "Expected 3, got %d\n", ref);
506     IStream_Release(stream);
507
508     /* try ::SetInput() with valid IXmlReaderInput */
509     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
510     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
511
512     ref = IUnknown_AddRef(reader_input);
513     ok(ref == 2, "Expected 2, got %d\n", ref);
514     IUnknown_Release(reader_input);
515
516     hr = IXmlReader_SetInput(reader, reader_input);
517     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
518
519     test_read_state(reader, XmlReadState_Initial, -1, FALSE);
520
521     nodetype = XmlNodeType_Element;
522     hr = IXmlReader_GetNodeType(reader, &nodetype);
523     ok(hr == S_OK, "got %08x\n", hr);
524     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
525
526     /* IXmlReader grabs a IXmlReaderInput reference */
527     ref = IUnknown_AddRef(reader_input);
528     ok(ref == 3, "Expected 3, got %d\n", ref);
529     IUnknown_Release(reader_input);
530
531     ref = IStream_AddRef(stream);
532     ok(ref == 4, "Expected 4, got %d\n", ref);
533     IStream_Release(stream);
534
535     /* reset input and check state */
536     hr = IXmlReader_SetInput(reader, NULL);
537     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
538
539     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
540
541     IXmlReader_Release(reader);
542
543     ref = IStream_AddRef(stream);
544     ok(ref == 3, "Expected 3, got %d\n", ref);
545     IStream_Release(stream);
546
547     ref = IUnknown_AddRef(reader_input);
548     ok(ref == 2, "Expected 2, got %d\n", ref);
549     IUnknown_Release(reader_input);
550
551     /* IID_IXmlReaderInput */
552     /* it returns a kind of private undocumented vtable incompatible with IUnknown,
553        so it's not a COM interface actually.
554        Such query will be used only to check if input is really IXmlReaderInput */
555     obj = (IUnknown*)0xdeadbeef;
556     hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
557     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
558     ref = IUnknown_AddRef(reader_input);
559     ok(ref == 3, "Expected 3, got %d\n", ref);
560     IUnknown_Release(reader_input);
561
562     IUnknown_Release(reader_input);
563     IUnknown_Release(reader_input);
564     IStream_Release(stream);
565
566     /* test input interface selection sequence */
567     input = NULL;
568     hr = testinput_createinstance((void**)&input);
569     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
570
571     input_iids.count = 0;
572     ref = IUnknown_AddRef(input);
573     ok(ref == 2, "Expected 2, got %d\n", ref);
574     IUnknown_Release(input);
575     hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
576     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
577     ok_iids(&input_iids, empty_seq, NULL, FALSE);
578     /* IXmlReaderInput stores stream interface as IUnknown */
579     ref = IUnknown_AddRef(input);
580     ok(ref == 3, "Expected 3, got %d\n", ref);
581     IUnknown_Release(input);
582
583     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
584     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
585
586     input_iids.count = 0;
587     ref = IUnknown_AddRef(reader_input);
588     ok(ref == 2, "Expected 2, got %d\n", ref);
589     IUnknown_Release(reader_input);
590     ref = IUnknown_AddRef(input);
591     ok(ref == 3, "Expected 3, got %d\n", ref);
592     IUnknown_Release(input);
593     hr = IXmlReader_SetInput(reader, reader_input);
594     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
595     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
596
597     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
598
599     ref = IUnknown_AddRef(input);
600     ok(ref == 3, "Expected 3, got %d\n", ref);
601     IUnknown_Release(input);
602
603     ref = IUnknown_AddRef(reader_input);
604     ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
605           "Expected 3, got %d\n", ref);
606     IUnknown_Release(reader_input);
607     /* repeat another time, no check or caching here */
608     input_iids.count = 0;
609     hr = IXmlReader_SetInput(reader, reader_input);
610     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
611     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
612
613     /* another reader */
614     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
615     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
616
617     /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
618        ::SetInput() level, each time it's called */
619     input_iids.count = 0;
620     hr = IXmlReader_SetInput(reader2, reader_input);
621     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
622     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
623
624     IXmlReader_Release(reader2);
625     IXmlReader_Release(reader);
626
627     IUnknown_Release(reader_input);
628     IUnknown_Release(input);
629 }
630
631 static void test_reader_state(void)
632 {
633     IXmlReader *reader;
634     XmlNodeType nodetype;
635     HRESULT hr;
636
637     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
638     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
639
640     /* invalid arguments */
641     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
642     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
643
644     /* attempt to read on closed reader */
645     test_read_state(reader, XmlReadState_Closed, -1, 0);
646 if (0)
647 {
648     /* newer versions crash here, probably cause no input was set */
649     hr = IXmlReader_Read(reader, &nodetype);
650     ok(hr == S_FALSE, "got %08x\n", hr);
651 }
652     IXmlReader_Release(reader);
653 }
654
655 static void test_read_xmldeclaration(void)
656 {
657     IXmlReader *reader;
658     IStream *stream;
659     HRESULT hr;
660     XmlNodeType type;
661     UINT count = 0;
662     const WCHAR *val;
663
664     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
665     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
666
667     /* position methods with Null args */
668     hr = IXmlReader_GetLineNumber(reader, NULL);
669     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
670
671     hr = IXmlReader_GetLinePosition(reader, NULL);
672     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
673
674     stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
675
676     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
677     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
678
679     hr = IXmlReader_GetAttributeCount(reader, &count);
680     ok(hr == S_OK, "got %08x\n", hr);
681     ok(count == 0, "got %d\n", count);
682
683     /* try to move without attributes */
684     hr = IXmlReader_MoveToElement(reader);
685     ok(hr == S_FALSE, "got %08x\n", hr);
686
687     hr = IXmlReader_MoveToNextAttribute(reader);
688     ok(hr == S_FALSE, "got %08x\n", hr);
689
690     hr = IXmlReader_MoveToFirstAttribute(reader);
691     ok(hr == S_FALSE, "got %08x\n", hr);
692
693     ok_pos(reader, 0, 0, -1, -1, FALSE);
694
695     type = -1;
696     hr = IXmlReader_Read(reader, &type);
697     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
698     ok(type == XmlNodeType_XmlDeclaration,
699                      "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
700     /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
701     ok_pos(reader, 1, 3, -1, 55, TRUE);
702     test_read_state(reader, XmlReadState_Interactive, -1, 0);
703
704     hr = IXmlReader_GetValue(reader, &val, NULL);
705     ok(hr == S_OK, "got %08x\n", hr);
706     ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
707
708     /* check attributes */
709     hr = IXmlReader_MoveToNextAttribute(reader);
710     ok(hr == S_OK, "got %08x\n", hr);
711
712     type = XmlNodeType_None;
713     hr = IXmlReader_GetNodeType(reader, &type);
714     ok(hr == S_OK, "got %08x\n", hr);
715     ok(type == XmlNodeType_Attribute, "got %d\n", type);
716
717     ok_pos(reader, 1, 7, -1, 55, TRUE);
718
719     /* try to move from last attribute */
720     hr = IXmlReader_MoveToNextAttribute(reader);
721     ok(hr == S_OK, "got %08x\n", hr);
722     hr = IXmlReader_MoveToNextAttribute(reader);
723     ok(hr == S_OK, "got %08x\n", hr);
724     hr = IXmlReader_MoveToNextAttribute(reader);
725     ok(hr == S_FALSE, "got %08x\n", hr);
726
727     type = XmlNodeType_None;
728     hr = IXmlReader_GetNodeType(reader, &type);
729     ok(hr == S_OK, "got %08x\n", hr);
730     ok(type == XmlNodeType_Attribute, "got %d\n", type);
731
732     hr = IXmlReader_MoveToFirstAttribute(reader);
733     ok(hr == S_OK, "got %08x\n", hr);
734     ok_pos(reader, 1, 7, -1, 55, TRUE);
735
736     hr = IXmlReader_GetAttributeCount(reader, NULL);
737     ok(hr == E_INVALIDARG, "got %08x\n", hr);
738
739     hr = IXmlReader_GetAttributeCount(reader, &count);
740     ok(hr == S_OK, "got %08x\n", hr);
741     ok(count == 3, "Expected 3, got %d\n", count);
742
743     hr = IXmlReader_GetDepth(reader, &count);
744     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
745 todo_wine
746     ok(count == 1, "Expected 1, got %d\n", count);
747
748     hr = IXmlReader_MoveToElement(reader);
749     ok(hr == S_OK, "got %08x\n", hr);
750
751     type = XmlNodeType_None;
752     hr = IXmlReader_GetNodeType(reader, &type);
753     ok(hr == S_OK, "got %08x\n", hr);
754     ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type);
755
756     type = XmlNodeType_XmlDeclaration;
757     hr = IXmlReader_Read(reader, &type);
758     /* newer versions return syntax error here cause document is incomplete,
759        it makes more sense than invalid char error */
760 todo_wine {
761     ok(hr == WC_E_SYNTAX || broken(hr == WC_E_XMLCHARACTER), "got 0x%08x\n", hr);
762     ok(type == XmlNodeType_None, "got %d\n", type);
763 }
764     IStream_Release(stream);
765     IXmlReader_Release(reader);
766 }
767
768 struct test_entry {
769     const char *xml;
770     const char *name;
771     const char *value;
772     HRESULT hr;
773     HRESULT hr_broken; /* this is set to older version results */
774     int todo : 1;
775 };
776
777 static struct test_entry comment_tests[] = {
778     { "<!-- comment -->", "", " comment ", S_OK },
779     { "<!-- - comment-->", "", " - comment", S_OK },
780     { "<!-- -- comment-->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
781     { "<!-- -- comment--->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
782     { NULL }
783 };
784
785 static void test_read_comment(void)
786 {
787     struct test_entry *test = comment_tests;
788     IXmlReader *reader;
789     HRESULT hr;
790
791     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
792     ok(hr == S_OK, "S_OK, got %08x\n", hr);
793
794     while (test->xml)
795     {
796         XmlNodeType type;
797         IStream *stream;
798
799         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
800         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
801         ok(hr == S_OK, "got %08x\n", hr);
802
803         type = XmlNodeType_None;
804         hr = IXmlReader_Read(reader, &type);
805         if (test->hr_broken)
806             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
807         else
808             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
809         if (hr == S_OK)
810         {
811             const WCHAR *str;
812             WCHAR *str_exp;
813             UINT len;
814
815             ok(type == XmlNodeType_Comment, "got %d for %s\n", type, test->xml);
816
817             len = 1;
818             str = NULL;
819             hr = IXmlReader_GetLocalName(reader, &str, &len);
820             ok(hr == S_OK, "got 0x%08x\n", hr);
821             ok(len == strlen(test->name), "got %u\n", len);
822             str_exp = a2w(test->name);
823             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
824             free_str(str_exp);
825
826             len = 1;
827             str = NULL;
828             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
829             ok(hr == S_OK, "got 0x%08x\n", hr);
830             ok(len == strlen(test->name), "got %u\n", len);
831             str_exp = a2w(test->name);
832             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
833             free_str(str_exp);
834
835             /* value */
836             len = 1;
837             str = NULL;
838             hr = IXmlReader_GetValue(reader, &str, &len);
839             ok(hr == S_OK, "got 0x%08x\n", hr);
840             ok(len == strlen(test->value), "got %u\n", len);
841             str_exp = a2w(test->value);
842             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
843             free_str(str_exp);
844         }
845
846         IStream_Release(stream);
847         test++;
848     }
849
850     IXmlReader_Release(reader);
851 }
852
853 static struct test_entry pi_tests[] = {
854     { "<?pi?>", "pi", "", S_OK },
855     { "<?pi ?>", "pi", "", S_OK },
856     { "<?pi  ?>", "pi", "", S_OK },
857     { "<?pi pi data?>", "pi", "pi data", S_OK },
858     { "<?pi pi data  ?>", "pi", "pi data  ", S_OK },
859     { "<?pi:pi?>", NULL, NULL, NC_E_NAMECOLON, WC_E_NAMECHARACTER },
860     { "<?:pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
861     { "<?-pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
862     { "<?xml-stylesheet ?>", "xml-stylesheet", "", S_OK },
863     { NULL }
864 };
865
866 static void test_read_pi(void)
867 {
868     struct test_entry *test = pi_tests;
869     IXmlReader *reader;
870     HRESULT hr;
871
872     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
873     ok(hr == S_OK, "S_OK, got %08x\n", hr);
874
875     while (test->xml)
876     {
877         XmlNodeType type;
878         IStream *stream;
879
880         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
881         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
882         ok(hr == S_OK, "got %08x\n", hr);
883
884         type = XmlNodeType_None;
885         hr = IXmlReader_Read(reader, &type);
886         if (test->hr_broken)
887             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
888         else
889             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
890         if (hr == S_OK)
891         {
892             const WCHAR *str;
893             WCHAR *str_exp;
894             UINT len;
895
896             ok(type == XmlNodeType_ProcessingInstruction, "got %d for %s\n", type, test->xml);
897
898             len = 0;
899             str = NULL;
900             hr = IXmlReader_GetLocalName(reader, &str, &len);
901             ok(hr == S_OK, "got 0x%08x\n", hr);
902             ok(len == strlen(test->name), "got %u\n", len);
903             str_exp = a2w(test->name);
904             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
905             free_str(str_exp);
906
907             len = 0;
908             str = NULL;
909             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
910             ok(hr == S_OK, "got 0x%08x\n", hr);
911             ok(len == strlen(test->name), "got %u\n", len);
912             str_exp = a2w(test->name);
913             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
914             free_str(str_exp);
915
916             /* value */
917             len = !strlen(test->value);
918             str = NULL;
919             hr = IXmlReader_GetValue(reader, &str, &len);
920             ok(hr == S_OK, "got 0x%08x\n", hr);
921             ok(len == strlen(test->value), "got %u\n", len);
922             str_exp = a2w(test->value);
923             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
924             free_str(str_exp);
925         }
926
927         IStream_Release(stream);
928         test++;
929     }
930
931     IXmlReader_Release(reader);
932 }
933
934 struct nodes_test {
935     const char *xml;
936     XmlNodeType types[20];
937 };
938
939 static const char misc_test_xml[] =
940     "<!-- comment1 -->"
941     "<!-- comment2 -->"
942     "<?pi1 pi1body ?>"
943     "<!-- comment3 -->"
944     " \t \r \n"
945     "<!-- comment4 -->"
946     "<a>"
947     "<b/>"
948     "<!-- comment -->"
949     "<?pi pibody ?>"
950     "</a>"
951 ;
952
953 static struct nodes_test misc_test = {
954     misc_test_xml,
955     {
956         XmlNodeType_Comment,
957         XmlNodeType_Comment,
958         XmlNodeType_ProcessingInstruction,
959         XmlNodeType_Comment,
960         XmlNodeType_Whitespace,
961         XmlNodeType_Comment,
962         XmlNodeType_Element,
963         XmlNodeType_Element,
964         XmlNodeType_Comment,
965         XmlNodeType_ProcessingInstruction,
966         XmlNodeType_EndElement,
967         XmlNodeType_None
968     }
969 };
970
971 static void test_read_full(void)
972 {
973     struct nodes_test *test = &misc_test;
974     IXmlReader *reader;
975     XmlNodeType type;
976     IStream *stream;
977     HRESULT hr;
978     int i;
979
980     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
981     ok(hr == S_OK, "S_OK, got %08x\n", hr);
982
983     stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
984     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
985     ok(hr == S_OK, "got %08x\n", hr);
986
987     i = 0;
988     type = XmlNodeType_None;
989     hr = IXmlReader_Read(reader, &type);
990     while (hr == S_OK)
991     {
992         ok(test->types[i] != XmlNodeType_None, "%d: unexpected end of test data\n", i);
993         if (test->types[i] == XmlNodeType_None) break;
994         ok(type == test->types[i], "%d: got wrong type %d, expected %d\n", i, type, test->types[i]);
995         hr = IXmlReader_Read(reader, &type);
996         i++;
997     }
998     ok(test->types[i] == XmlNodeType_None, "incomplete sequence, got %d\n", test->types[i]);
999
1000     IStream_Release(stream);
1001     IXmlReader_Release(reader);
1002 }
1003
1004 static const char test_dtd[] =
1005     "<!DOCTYPE testdtd SYSTEM \"externalid uri\" >"
1006     "<!-- comment -->";
1007
1008 static void test_read_dtd(void)
1009 {
1010     static const WCHAR sysvalW[] = {'e','x','t','e','r','n','a','l','i','d',' ','u','r','i',0};
1011     static const WCHAR dtdnameW[] = {'t','e','s','t','d','t','d',0};
1012     static const WCHAR sysW[] = {'S','Y','S','T','E','M',0};
1013     IXmlReader *reader;
1014     const WCHAR *str;
1015     XmlNodeType type;
1016     IStream *stream;
1017     UINT len, count;
1018     HRESULT hr;
1019
1020     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1021     ok(hr == S_OK, "S_OK, got %08x\n", hr);
1022
1023     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, DtdProcessing_Parse);
1024     ok(hr == S_OK, "got 0x%8x\n", hr);
1025
1026     stream = create_stream_on_data(test_dtd, sizeof(test_dtd));
1027     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1028     ok(hr == S_OK, "got %08x\n", hr);
1029
1030     type = XmlNodeType_None;
1031     hr = IXmlReader_Read(reader, &type);
1032     ok(hr == S_OK, "got 0x%8x\n", hr);
1033     ok(type == XmlNodeType_DocumentType, "got type %d\n", type);
1034
1035     count = 0;
1036     hr = IXmlReader_GetAttributeCount(reader, &count);
1037     ok(hr == S_OK, "got %08x\n", hr);
1038     ok(count == 1, "got %d\n", count);
1039
1040     hr = IXmlReader_MoveToFirstAttribute(reader);
1041     ok(hr == S_OK, "got %08x\n", hr);
1042
1043     type = XmlNodeType_None;
1044     hr = IXmlReader_GetNodeType(reader, &type);
1045     ok(hr == S_OK, "got %08x\n", hr);
1046     ok(type == XmlNodeType_Attribute, "got %d\n", type);
1047
1048     len = 0;
1049     str = NULL;
1050     hr = IXmlReader_GetLocalName(reader, &str, &len);
1051     ok(hr == S_OK, "got 0x%08x\n", hr);
1052 todo_wine {
1053     ok(len == lstrlenW(sysW), "got %u\n", len);
1054     ok(!lstrcmpW(str, sysW), "got %s\n", wine_dbgstr_w(str));
1055 }
1056     len = 0;
1057     str = NULL;
1058     hr = IXmlReader_GetValue(reader, &str, &len);
1059     ok(hr == S_OK, "got 0x%08x\n", hr);
1060 todo_wine {
1061     ok(len == lstrlenW(sysvalW), "got %u\n", len);
1062     ok(!lstrcmpW(str, sysvalW), "got %s\n", wine_dbgstr_w(str));
1063 }
1064     hr = IXmlReader_MoveToElement(reader);
1065     ok(hr == S_OK, "got 0x%08x\n", hr);
1066
1067     len = 0;
1068     str = NULL;
1069     hr = IXmlReader_GetLocalName(reader, &str, &len);
1070     ok(hr == S_OK, "got 0x%08x\n", hr);
1071     ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1072     ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1073
1074     len = 0;
1075     str = NULL;
1076     hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1077     ok(hr == S_OK, "got 0x%08x\n", hr);
1078     ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1079     ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1080
1081     type = XmlNodeType_None;
1082     hr = IXmlReader_Read(reader, &type);
1083     ok(hr == S_OK, "got 0x%8x\n", hr);
1084     ok(type == XmlNodeType_Comment, "got type %d\n", type);
1085
1086     IStream_Release(stream);
1087     IXmlReader_Release(reader);
1088 }
1089
1090 static struct test_entry element_tests[] = {
1091     { "<a/>", "a", "", S_OK },
1092     { "<a />", "a", "", S_OK },
1093     { "<a:b/>", "a:b", "", NC_E_UNDECLAREDPREFIX },
1094     { "<:a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1095     { "< a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1096     { "<a>", "a", "", S_OK },
1097     { "<a >", "a", "", S_OK },
1098     { "<a \r \t\n>", "a", "", S_OK },
1099     { "</a>", NULL, NULL, NC_E_QNAMECHARACTER },
1100     { NULL }
1101 };
1102
1103 static void test_read_element(void)
1104 {
1105     struct test_entry *test = element_tests;
1106     static const char stag[] = "<a><b></b></a>";
1107     static const char mismatch[] = "<a></b>";
1108     IXmlReader *reader;
1109     XmlNodeType type;
1110     IStream *stream;
1111     UINT depth;
1112     HRESULT hr;
1113
1114     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1115     ok(hr == S_OK, "S_OK, got %08x\n", hr);
1116
1117     while (test->xml)
1118     {
1119         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1120         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1121         ok(hr == S_OK, "got %08x\n", hr);
1122
1123         type = XmlNodeType_None;
1124         hr = IXmlReader_Read(reader, &type);
1125         if (test->hr_broken)
1126             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1127         else
1128             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1129         if (hr == S_OK)
1130         {
1131             const WCHAR *str;
1132             WCHAR *str_exp;
1133             UINT len;
1134
1135             ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
1136
1137             len = 0;
1138             str = NULL;
1139             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1140             ok(hr == S_OK, "got 0x%08x\n", hr);
1141             ok(len == strlen(test->name), "got %u\n", len);
1142             str_exp = a2w(test->name);
1143             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1144             free_str(str_exp);
1145
1146             /* value */
1147             len = 1;
1148             str = NULL;
1149             hr = IXmlReader_GetValue(reader, &str, &len);
1150             ok(hr == S_OK, "got 0x%08x\n", hr);
1151             ok(len == 0, "got %u\n", len);
1152             ok(*str == 0, "got %s\n", wine_dbgstr_w(str));
1153         }
1154
1155         IStream_Release(stream);
1156         test++;
1157     }
1158
1159     /* test reader depth increment */
1160     stream = create_stream_on_data(stag, sizeof(stag));
1161     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1162     ok(hr == S_OK, "got %08x\n", hr);
1163
1164     depth = 1;
1165     hr = IXmlReader_GetDepth(reader, &depth);
1166     ok(hr == S_OK, "got %08x\n", hr);
1167     ok(depth == 0, "got %d\n", depth);
1168
1169     hr = IXmlReader_Read(reader, &type);
1170     ok(hr == S_OK, "got %08x\n", hr);
1171
1172     depth = 1;
1173     hr = IXmlReader_GetDepth(reader, &depth);
1174     ok(hr == S_OK, "got %08x\n", hr);
1175     ok(depth == 0, "got %d\n", depth);
1176
1177     hr = IXmlReader_Read(reader, &type);
1178     ok(hr == S_OK, "got %08x\n", hr);
1179
1180     depth = 0;
1181     hr = IXmlReader_GetDepth(reader, &depth);
1182     ok(hr == S_OK, "got %08x\n", hr);
1183     ok(depth == 1, "got %d\n", depth);
1184
1185     /* read end tag for inner element */
1186     type = XmlNodeType_None;
1187     hr = IXmlReader_Read(reader, &type);
1188     ok(hr == S_OK, "got %08x\n", hr);
1189     ok(type == XmlNodeType_EndElement, "got %d\n", type);
1190
1191     depth = 0;
1192     hr = IXmlReader_GetDepth(reader, &depth);
1193     ok(hr == S_OK, "got %08x\n", hr);
1194 todo_wine
1195     ok(depth == 2, "got %d\n", depth);
1196
1197     /* read end tag for container element */
1198     type = XmlNodeType_None;
1199     hr = IXmlReader_Read(reader, &type);
1200     ok(hr == S_OK, "got %08x\n", hr);
1201     ok(type == XmlNodeType_EndElement, "got %d\n", type);
1202
1203     depth = 0;
1204     hr = IXmlReader_GetDepth(reader, &depth);
1205     ok(hr == S_OK, "got %08x\n", hr);
1206     ok(depth == 1, "got %d\n", depth);
1207
1208     IStream_Release(stream);
1209
1210     /* start/end tag mismatch */
1211     stream = create_stream_on_data(mismatch, sizeof(mismatch));
1212     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1213     ok(hr == S_OK, "got %08x\n", hr);
1214
1215     type = XmlNodeType_None;
1216     hr = IXmlReader_Read(reader, &type);
1217     ok(hr == S_OK, "got %08x\n", hr);
1218     ok(type == XmlNodeType_Element, "got %d\n", type);
1219
1220     type = XmlNodeType_Element;
1221     hr = IXmlReader_Read(reader, &type);
1222     ok(hr == WC_E_ELEMENTMATCH, "got %08x\n", hr);
1223 todo_wine
1224     ok(type == XmlNodeType_None, "got %d\n", type);
1225
1226     IStream_Release(stream);
1227
1228     IXmlReader_Release(reader);
1229 }
1230
1231 static ISequentialStream teststream = { &teststreamvtbl };
1232
1233 static void test_read_pending(void)
1234 {
1235     IXmlReader *reader;
1236     const WCHAR *value;
1237     XmlNodeType type;
1238     HRESULT hr;
1239     int c;
1240
1241     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1242     ok(hr == S_OK, "S_OK, got 0x%08x\n", hr);
1243
1244     hr = IXmlReader_SetInput(reader, (IUnknown*)&teststream);
1245     ok(hr == S_OK, "got 0x%08x\n", hr);
1246
1247     /* first read call returns incomplete node, second attempt fails with E_PENDING */
1248     stream_readcall = 0;
1249     type = XmlNodeType_Element;
1250     hr = IXmlReader_Read(reader, &type);
1251     ok(hr == S_OK || broken(hr == E_PENDING), "got 0x%08x\n", hr);
1252     /* newer versions are happy when it's enough data to detect node type,
1253        older versions keep reading until it fails to read more */
1254     ok(stream_readcall == 1 || broken(stream_readcall > 1), "got %d\n", stream_readcall);
1255     ok(type == XmlNodeType_Comment || broken(type == XmlNodeType_None), "got %d\n", type);
1256
1257     /* newer versions' GetValue() makes an attempt to read more */
1258     c = stream_readcall;
1259     value = (void*)0xdeadbeef;
1260     hr = IXmlReader_GetValue(reader, &value, NULL);
1261     ok(hr == E_PENDING, "got 0x%08x\n", hr);
1262     ok(value == NULL || broken(value == (void*)0xdeadbeef) /* Win8 sets it to NULL */, "got %p\n", value);
1263     ok(c < stream_readcall || broken(c == stream_readcall), "got %d, expected %d\n", stream_readcall, c+1);
1264
1265     IXmlReader_Release(reader);
1266 }
1267
1268 static void test_readvaluechunk(void)
1269 {
1270     static const char testA[] = "<!-- comment1 -->";
1271     IXmlReader *reader;
1272     XmlNodeType type;
1273     IStream *stream;
1274     const WCHAR *value;
1275     WCHAR b;
1276     HRESULT hr;
1277     UINT c;
1278
1279     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1280     ok(hr == S_OK, "S_OK, got %08x\n", hr);
1281
1282     stream = create_stream_on_data(testA, sizeof(testA));
1283     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1284     ok(hr == S_OK, "got %08x\n", hr);
1285
1286     hr = IXmlReader_Read(reader, &type);
1287     ok(hr == S_OK, "got %08x\n", hr);
1288
1289     c = 0;
1290     b = 0;
1291     hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1292     ok(hr == S_OK, "got %08x\n", hr);
1293     ok(c == 1, "got %u\n", c);
1294     ok(b == ' ', "got %x\n", b);
1295
1296     /* portion read as chunk is skipped from resulting node value */
1297     value = NULL;
1298     hr = IXmlReader_GetValue(reader, &value, NULL);
1299     ok(hr == S_OK, "got %08x\n", hr);
1300     ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1301
1302     /* once value is returned/allocated it's not possible to read by chunk */
1303     c = 0;
1304     b = 0;
1305     hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1306     ok(hr == S_FALSE, "got %08x\n", hr);
1307     ok(c == 0, "got %u\n", c);
1308     ok(b == 0, "got %x\n", b);
1309
1310     value = NULL;
1311     hr = IXmlReader_GetValue(reader, &value, NULL);
1312     ok(hr == S_OK, "got %08x\n", hr);
1313     ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1314
1315     IXmlReader_Release(reader);
1316 }
1317
1318 static struct test_entry cdata_tests[] = {
1319     { "<a><![CDATA[ ]]data ]]></a>", "", " ]]data ", S_OK },
1320     { "<a><![CDATA[<![CDATA[ data ]]]]></a>", "", "<![CDATA[ data ]]", S_OK },
1321     { "<a><![CDATA[\n \r\n \n\n ]]></a>", "", "\n \n \n\n ", S_OK, S_OK, 1 },
1322     { "<a><![CDATA[\r \r\r\n \n\n ]]></a>", "", "\n \n\n \n\n ", S_OK, S_OK, 1 },
1323     { "<a><![CDATA[\r\r \n\r \r \n\n ]]></a>", "", "\n\n \n\n \n \n\n ", S_OK },
1324     { NULL }
1325 };
1326
1327 static void test_read_cdata(void)
1328 {
1329     struct test_entry *test = cdata_tests;
1330     IXmlReader *reader;
1331     HRESULT hr;
1332
1333     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1334     ok(hr == S_OK, "S_OK, got %08x\n", hr);
1335
1336     while (test->xml)
1337     {
1338         XmlNodeType type;
1339         IStream *stream;
1340
1341         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1342         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1343         ok(hr == S_OK, "got %08x\n", hr);
1344
1345         type = XmlNodeType_None;
1346         hr = IXmlReader_Read(reader, &type);
1347
1348         /* read one more to get to CDATA */
1349         if (type == XmlNodeType_Element)
1350         {
1351             type = XmlNodeType_None;
1352             hr = IXmlReader_Read(reader, &type);
1353         }
1354
1355         if (test->hr_broken)
1356             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1357         else
1358             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1359         if (hr == S_OK)
1360         {
1361             const WCHAR *str;
1362             WCHAR *str_exp;
1363             UINT len;
1364
1365             ok(type == XmlNodeType_CDATA, "got %d for %s\n", type, test->xml);
1366
1367             len = 1;
1368             str = NULL;
1369             hr = IXmlReader_GetLocalName(reader, &str, &len);
1370             ok(hr == S_OK, "got 0x%08x\n", hr);
1371             ok(len == strlen(test->name), "got %u\n", len);
1372             str_exp = a2w(test->name);
1373             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1374             free_str(str_exp);
1375
1376             len = 1;
1377             str = NULL;
1378             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1379             ok(hr == S_OK, "got 0x%08x\n", hr);
1380             ok(len == strlen(test->name), "got %u\n", len);
1381             str_exp = a2w(test->name);
1382             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1383             free_str(str_exp);
1384
1385             /* value */
1386             len = 1;
1387             str = NULL;
1388             hr = IXmlReader_GetValue(reader, &str, &len);
1389             ok(hr == S_OK, "got 0x%08x\n", hr);
1390
1391             str_exp = a2w(test->value);
1392             if (test->todo)
1393             {
1394             todo_wine {
1395                 ok(len == strlen(test->value), "got %u\n", len);
1396                 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1397             }
1398             }
1399             else
1400             {
1401                 ok(len == strlen(test->value), "got %u\n", len);
1402                 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1403             }
1404             free_str(str_exp);
1405         }
1406
1407         IStream_Release(stream);
1408         test++;
1409     }
1410
1411     IXmlReader_Release(reader);
1412 }
1413
1414 START_TEST(reader)
1415 {
1416     HRESULT r;
1417
1418     r = CoInitialize( NULL );
1419     ok( r == S_OK, "failed to init com\n");
1420
1421     if (!init_pointers())
1422     {
1423        CoUninitialize();
1424        return;
1425     }
1426
1427     test_reader_create();
1428     test_readerinput();
1429     test_reader_state();
1430     test_read_cdata();
1431     test_read_comment();
1432     test_read_pi();
1433     test_read_dtd();
1434     test_read_element();
1435     test_read_full();
1436     test_read_pending();
1437     test_readvaluechunk();
1438     test_read_xmldeclaration();
1439
1440     CoUninitialize();
1441 }