crypt32: Free the encoded msg (Coverity).
[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 BOOL init_pointers(void)
343 {
344     /* don't free module here, it's to be unloaded on exit */
345     HMODULE mod = LoadLibraryA("xmllite.dll");
346
347     if (!mod)
348     {
349         win_skip("xmllite library not available\n");
350         return FALSE;
351     }
352
353 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
354     MAKEFUNC(CreateXmlReader);
355     MAKEFUNC(CreateXmlReaderInputWithEncodingName);
356 #undef MAKEFUNC
357
358     return TRUE;
359 }
360
361 static void test_reader_create(void)
362 {
363     HRESULT hr;
364     IXmlReader *reader;
365     IUnknown *input;
366     DtdProcessing dtd;
367     XmlNodeType nodetype;
368
369     /* crashes native */
370     if (0)
371     {
372         pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
373         pCreateXmlReader(NULL, (void**)&reader, NULL);
374     }
375
376     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
377     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
378
379     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
380
381     nodetype = XmlNodeType_Element;
382     hr = IXmlReader_GetNodeType(reader, &nodetype);
383     ok(hr == S_FALSE, "got %08x\n", hr);
384     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
385
386     dtd = 2;
387     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
388     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
389     ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
390
391     dtd = 2;
392     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
393     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
394
395     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
396     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
397
398     /* Null input pointer, releases previous input */
399     hr = IXmlReader_SetInput(reader, NULL);
400     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
401
402     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
403
404     /* test input interface selection sequence */
405     hr = testinput_createinstance((void**)&input);
406     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
407
408     if (hr == S_OK)
409     {
410         input_iids.count = 0;
411         hr = IXmlReader_SetInput(reader, input);
412         ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
413         ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
414         IUnknown_Release(input);
415     }
416     IXmlReader_Release(reader);
417 }
418
419 static void test_readerinput(void)
420 {
421     IXmlReaderInput *reader_input;
422     IXmlReader *reader, *reader2;
423     IUnknown *obj, *input;
424     IStream *stream, *stream2;
425     XmlNodeType nodetype;
426     HRESULT hr;
427     LONG ref;
428
429     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
430     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
431     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
432     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
433
434     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
435     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
436
437     ref = IStream_AddRef(stream);
438     ok(ref == 2, "Expected 2, got %d\n", ref);
439     IStream_Release(stream);
440     hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
441     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
442
443     hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
444     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
445
446     hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
447     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
448
449     /* IXmlReaderInput grabs a stream reference */
450     ref = IStream_AddRef(stream);
451     ok(ref == 3, "Expected 3, got %d\n", ref);
452     IStream_Release(stream);
453
454     /* try ::SetInput() with valid IXmlReaderInput */
455     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
456     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
457
458     ref = IUnknown_AddRef(reader_input);
459     ok(ref == 2, "Expected 2, got %d\n", ref);
460     IUnknown_Release(reader_input);
461
462     hr = IXmlReader_SetInput(reader, reader_input);
463     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
464
465     test_read_state(reader, XmlReadState_Initial, -1, FALSE);
466
467     nodetype = XmlNodeType_Element;
468     hr = IXmlReader_GetNodeType(reader, &nodetype);
469     ok(hr == S_OK, "got %08x\n", hr);
470     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
471
472     /* IXmlReader grabs a IXmlReaderInput reference */
473     ref = IUnknown_AddRef(reader_input);
474     ok(ref == 3, "Expected 3, got %d\n", ref);
475     IUnknown_Release(reader_input);
476
477     ref = IStream_AddRef(stream);
478     ok(ref == 4, "Expected 4, got %d\n", ref);
479     IStream_Release(stream);
480
481     /* reset input and check state */
482     hr = IXmlReader_SetInput(reader, NULL);
483     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
484
485     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
486
487     IXmlReader_Release(reader);
488
489     ref = IStream_AddRef(stream);
490     ok(ref == 3, "Expected 3, got %d\n", ref);
491     IStream_Release(stream);
492
493     ref = IUnknown_AddRef(reader_input);
494     ok(ref == 2, "Expected 2, got %d\n", ref);
495     IUnknown_Release(reader_input);
496
497     /* IID_IXmlReaderInput */
498     /* it returns a kind of private undocumented vtable incompatible with IUnknown,
499        so it's not a COM interface actually.
500        Such query will be used only to check if input is really IXmlReaderInput */
501     obj = (IUnknown*)0xdeadbeef;
502     hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
503     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
504     ref = IUnknown_AddRef(reader_input);
505     ok(ref == 3, "Expected 3, got %d\n", ref);
506     IUnknown_Release(reader_input);
507
508     IUnknown_Release(reader_input);
509     IUnknown_Release(reader_input);
510     IStream_Release(stream);
511
512     /* test input interface selection sequence */
513     input = NULL;
514     hr = testinput_createinstance((void**)&input);
515     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
516
517     input_iids.count = 0;
518     ref = IUnknown_AddRef(input);
519     ok(ref == 2, "Expected 2, got %d\n", ref);
520     IUnknown_Release(input);
521     hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
522     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
523     ok_iids(&input_iids, empty_seq, NULL, FALSE);
524     /* IXmlReaderInput stores stream interface as IUnknown */
525     ref = IUnknown_AddRef(input);
526     ok(ref == 3, "Expected 3, got %d\n", ref);
527     IUnknown_Release(input);
528
529     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
530     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
531
532     input_iids.count = 0;
533     ref = IUnknown_AddRef(reader_input);
534     ok(ref == 2, "Expected 2, got %d\n", ref);
535     IUnknown_Release(reader_input);
536     ref = IUnknown_AddRef(input);
537     ok(ref == 3, "Expected 3, got %d\n", ref);
538     IUnknown_Release(input);
539     hr = IXmlReader_SetInput(reader, reader_input);
540     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
541     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
542
543     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
544
545     ref = IUnknown_AddRef(input);
546     ok(ref == 3, "Expected 3, got %d\n", ref);
547     IUnknown_Release(input);
548
549     ref = IUnknown_AddRef(reader_input);
550     ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
551           "Expected 3, got %d\n", ref);
552     IUnknown_Release(reader_input);
553     /* repeat another time, no check or caching here */
554     input_iids.count = 0;
555     hr = IXmlReader_SetInput(reader, reader_input);
556     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
557     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
558
559     /* another reader */
560     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
561     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
562
563     /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
564        ::SetInput() level, each time it's called */
565     input_iids.count = 0;
566     hr = IXmlReader_SetInput(reader2, reader_input);
567     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
568     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
569
570     IXmlReader_Release(reader2);
571     IXmlReader_Release(reader);
572
573     IUnknown_Release(reader_input);
574     IUnknown_Release(input);
575 }
576
577 static void test_reader_state(void)
578 {
579     IXmlReader *reader;
580     XmlNodeType nodetype;
581     HRESULT hr;
582
583     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
584     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
585
586     /* invalid arguments */
587     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
588     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
589
590     /* attempt to read on closed reader */
591     test_read_state(reader, XmlReadState_Closed, -1, 0);
592 if (0)
593 {
594     /* newer versions crash here, probably cause no input was set */
595     hr = IXmlReader_Read(reader, &nodetype);
596     ok(hr == S_FALSE, "got %08x\n", hr);
597 }
598     IXmlReader_Release(reader);
599 }
600
601 static void test_read_xmldeclaration(void)
602 {
603     IXmlReader *reader;
604     IStream *stream;
605     HRESULT hr;
606     XmlNodeType type;
607     UINT count = 0;
608     const WCHAR *val;
609
610     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
611     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
612
613     /* position methods with Null args */
614     hr = IXmlReader_GetLineNumber(reader, NULL);
615     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
616
617     hr = IXmlReader_GetLinePosition(reader, NULL);
618     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
619
620     stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
621
622     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
623     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
624
625     hr = IXmlReader_GetAttributeCount(reader, &count);
626     ok(hr == S_OK, "got %08x\n", hr);
627     ok(count == 0, "got %d\n", count);
628
629     /* try to move without attributes */
630     hr = IXmlReader_MoveToElement(reader);
631     ok(hr == S_FALSE, "got %08x\n", hr);
632
633     hr = IXmlReader_MoveToNextAttribute(reader);
634     ok(hr == S_FALSE, "got %08x\n", hr);
635
636     hr = IXmlReader_MoveToFirstAttribute(reader);
637     ok(hr == S_FALSE, "got %08x\n", hr);
638
639     ok_pos(reader, 0, 0, -1, -1, FALSE);
640
641     type = -1;
642     hr = IXmlReader_Read(reader, &type);
643     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
644     ok(type == XmlNodeType_XmlDeclaration,
645                      "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
646     /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
647     ok_pos(reader, 1, 3, -1, 55, TRUE);
648     test_read_state(reader, XmlReadState_Interactive, -1, 0);
649
650     hr = IXmlReader_GetValue(reader, &val, NULL);
651     ok(hr == S_OK, "got %08x\n", hr);
652     ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
653
654     /* check attributes */
655     hr = IXmlReader_MoveToNextAttribute(reader);
656     ok(hr == S_OK, "got %08x\n", hr);
657
658     type = XmlNodeType_None;
659     hr = IXmlReader_GetNodeType(reader, &type);
660     ok(hr == S_OK, "got %08x\n", hr);
661     ok(type == XmlNodeType_Attribute, "got %d\n", type);
662
663     ok_pos(reader, 1, 7, -1, 55, TRUE);
664
665     /* try to move from last attribute */
666     hr = IXmlReader_MoveToNextAttribute(reader);
667     ok(hr == S_OK, "got %08x\n", hr);
668     hr = IXmlReader_MoveToNextAttribute(reader);
669     ok(hr == S_OK, "got %08x\n", hr);
670     hr = IXmlReader_MoveToNextAttribute(reader);
671     ok(hr == S_FALSE, "got %08x\n", hr);
672
673     type = XmlNodeType_None;
674     hr = IXmlReader_GetNodeType(reader, &type);
675     ok(hr == S_OK, "got %08x\n", hr);
676     ok(type == XmlNodeType_Attribute, "got %d\n", type);
677
678     hr = IXmlReader_MoveToFirstAttribute(reader);
679     ok(hr == S_OK, "got %08x\n", hr);
680     ok_pos(reader, 1, 7, -1, 55, TRUE);
681
682     hr = IXmlReader_GetAttributeCount(reader, NULL);
683     ok(hr == E_INVALIDARG, "got %08x\n", hr);
684
685     hr = IXmlReader_GetAttributeCount(reader, &count);
686     ok(hr == S_OK, "got %08x\n", hr);
687     ok(count == 3, "Expected 3, got %d\n", count);
688
689     hr = IXmlReader_GetDepth(reader, &count);
690 todo_wine {
691     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
692     ok(count == 1, "Expected 1, got %d\n", count);
693 }
694
695     hr = IXmlReader_MoveToElement(reader);
696     ok(hr == S_OK, "got %08x\n", hr);
697
698     type = XmlNodeType_None;
699     hr = IXmlReader_GetNodeType(reader, &type);
700     ok(hr == S_OK, "got %08x\n", hr);
701     ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type);
702
703     type = XmlNodeType_XmlDeclaration;
704     hr = IXmlReader_Read(reader, &type);
705     /* newer versions return syntax error here cause document is incomplete,
706        it makes more sense than invalid char error */
707 todo_wine {
708     ok(hr == WC_E_SYNTAX || broken(hr == WC_E_XMLCHARACTER), "got 0x%08x\n", hr);
709     ok(type == XmlNodeType_None, "got %d\n", type);
710 }
711     IStream_Release(stream);
712     IXmlReader_Release(reader);
713 }
714
715 struct test_entry {
716     const char *xml;
717     const char *name;
718     const char *value;
719     HRESULT hr;
720     HRESULT hr_broken; /* this is set to older version results */
721 };
722
723 static struct test_entry comment_tests[] = {
724     { "<!-- comment -->", "", " comment ", S_OK },
725     { "<!-- - comment-->", "", " - comment", S_OK },
726     { "<!-- -- comment-->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
727     { "<!-- -- comment--->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
728     { NULL }
729 };
730
731 static void test_read_comment(void)
732 {
733     struct test_entry *test = comment_tests;
734     IXmlReader *reader;
735     HRESULT hr;
736
737     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
738     ok(hr == S_OK, "S_OK, got %08x\n", hr);
739
740     while (test->xml)
741     {
742         XmlNodeType type;
743         IStream *stream;
744
745         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
746         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
747         ok(hr == S_OK, "got %08x\n", hr);
748
749         type = XmlNodeType_None;
750         hr = IXmlReader_Read(reader, &type);
751         if (test->hr_broken)
752             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
753         else
754             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
755         if (hr == S_OK)
756         {
757             const WCHAR *str;
758             WCHAR *str_exp;
759             UINT len;
760
761             ok(type == XmlNodeType_Comment, "got %d for %s\n", type, test->xml);
762
763             len = 1;
764             str = NULL;
765             hr = IXmlReader_GetLocalName(reader, &str, &len);
766             ok(hr == S_OK, "got 0x%08x\n", hr);
767             ok(len == strlen(test->name), "got %u\n", len);
768             str_exp = a2w(test->name);
769             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
770             free_str(str_exp);
771
772             len = 1;
773             str = NULL;
774             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
775             ok(hr == S_OK, "got 0x%08x\n", hr);
776             ok(len == strlen(test->name), "got %u\n", len);
777             str_exp = a2w(test->name);
778             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
779             free_str(str_exp);
780
781             /* value */
782             len = 1;
783             str = NULL;
784             hr = IXmlReader_GetValue(reader, &str, &len);
785             ok(hr == S_OK, "got 0x%08x\n", hr);
786             ok(len == strlen(test->value), "got %u\n", len);
787             str_exp = a2w(test->value);
788             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
789             free_str(str_exp);
790         }
791
792         IStream_Release(stream);
793         test++;
794     }
795
796     IXmlReader_Release(reader);
797 }
798
799 static struct test_entry pi_tests[] = {
800     { "<?pi?>", "pi", "", S_OK },
801     { "<?pi ?>", "pi", "", S_OK },
802     { "<?pi pi data?>", "pi", "pi data", S_OK },
803     { "<?pi pi data  ?>", "pi", "pi data  ", S_OK },
804     { "<?pi:pi?>", NULL, NULL, NC_E_NAMECOLON, WC_E_NAMECHARACTER },
805     { "<?:pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
806     { "<?-pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
807     { "<?xml-stylesheet ?>", "xml-stylesheet", "", S_OK },
808     { NULL }
809 };
810
811 static void test_read_pi(void)
812 {
813     struct test_entry *test = pi_tests;
814     IXmlReader *reader;
815     HRESULT hr;
816
817     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
818     ok(hr == S_OK, "S_OK, got %08x\n", hr);
819
820     while (test->xml)
821     {
822         XmlNodeType type;
823         IStream *stream;
824
825         stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
826         hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
827         ok(hr == S_OK, "got %08x\n", hr);
828
829         type = XmlNodeType_None;
830         hr = IXmlReader_Read(reader, &type);
831         if (test->hr_broken)
832             ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
833         else
834             ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
835         if (hr == S_OK)
836         {
837             const WCHAR *str;
838             WCHAR *str_exp;
839             UINT len;
840
841             ok(type == XmlNodeType_ProcessingInstruction, "got %d for %s\n", type, test->xml);
842
843             len = 0;
844             str = NULL;
845             hr = IXmlReader_GetLocalName(reader, &str, &len);
846             ok(hr == S_OK, "got 0x%08x\n", hr);
847             ok(len == strlen(test->name), "got %u\n", len);
848             str_exp = a2w(test->name);
849             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
850             free_str(str_exp);
851
852             len = 0;
853             str = NULL;
854             hr = IXmlReader_GetQualifiedName(reader, &str, &len);
855             ok(hr == S_OK, "got 0x%08x\n", hr);
856             ok(len == strlen(test->name), "got %u\n", len);
857             str_exp = a2w(test->name);
858             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
859             free_str(str_exp);
860
861             /* value */
862             len = !strlen(test->value);
863             str = NULL;
864             hr = IXmlReader_GetValue(reader, &str, &len);
865             ok(hr == S_OK, "got 0x%08x\n", hr);
866             ok(len == strlen(test->value), "got %u\n", len);
867             str_exp = a2w(test->value);
868             ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
869             free_str(str_exp);
870         }
871
872         IStream_Release(stream);
873         test++;
874     }
875
876     IXmlReader_Release(reader);
877 }
878
879 START_TEST(reader)
880 {
881     HRESULT r;
882
883     r = CoInitialize( NULL );
884     ok( r == S_OK, "failed to init com\n");
885
886     if (!init_pointers())
887     {
888        CoUninitialize();
889        return;
890     }
891
892     test_reader_create();
893     test_readerinput();
894     test_reader_state();
895     test_read_comment();
896     test_read_pi();
897     test_read_xmldeclaration();
898
899     CoUninitialize();
900 }