uxtheme: Remove unused variable.
[wine] / dlls / xmllite / tests / reader.c
1 /*
2  * XMLLite IXmlReader tests
3  *
4  * Copyright 2010 (C) 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 const char xmldecl_full[] = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
56
57 static IStream *create_stream_on_data(const char *data, int size)
58 {
59     IStream *stream = NULL;
60     HGLOBAL hglobal;
61     void *ptr;
62     HRESULT hr;
63
64     hglobal = GlobalAlloc(GHND, size);
65     ptr = GlobalLock(hglobal);
66
67     memcpy(ptr, data, size);
68
69     hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
70     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
71     ok(stream != NULL, "Expected non-NULL stream\n");
72
73     GlobalUnlock(hglobal);
74
75     return stream;
76 }
77
78 static void ok_pos_(IXmlReader *reader, int line, int pos, int line_broken,
79                                            int pos_broken, int todo, int _line_)
80 {
81     UINT l, p;
82     HRESULT hr;
83     int broken_state;
84
85     hr = IXmlReader_GetLineNumber(reader, &l);
86     ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
87     hr = IXmlReader_GetLinePosition(reader, &p);
88     ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
89
90     if (line_broken == -1 && pos_broken == -1)
91         broken_state = 0;
92     else
93         broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
94                               (pos_broken == -1 ? pos : pos_broken) == p);
95
96     if (todo)
97         todo_wine
98         ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
99                             "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
100     else
101     {
102         ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
103                             "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
104     }
105 }
106 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
107
108 typedef struct input_iids_t {
109     IID iids[10];
110     int count;
111 } input_iids_t;
112
113 static const IID *setinput_full[] = {
114     &IID_IXmlReaderInput,
115     &IID_IStream,
116     &IID_ISequentialStream,
117     NULL
118 };
119
120 /* this applies to early xmllite versions */
121 static const IID *setinput_full_old[] = {
122     &IID_IXmlReaderInput,
123     &IID_ISequentialStream,
124     &IID_IStream,
125     NULL
126 };
127
128 /* after ::SetInput(IXmlReaderInput*) */
129 static const IID *setinput_readerinput[] = {
130     &IID_IStream,
131     &IID_ISequentialStream,
132     NULL
133 };
134
135 static const IID *empty_seq[] = {
136     NULL
137 };
138
139 static input_iids_t input_iids;
140
141 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line)
142 {
143     int i = 0, size = 0;
144
145     while (expected[i++]) size++;
146
147     if (todo) {
148         todo_wine
149             ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
150     }
151     else
152        ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
153
154     if (iids->count != size) return;
155
156     for (i = 0; i < size; i++) {
157         ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
158             (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
159             "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
160     }
161 }
162 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
163
164 static const char *state_to_str(XmlReadState state)
165 {
166     static const char* state_names[] = {
167         "XmlReadState_Initial",
168         "XmlReadState_Interactive",
169         "XmlReadState_Error",
170         "XmlReadState_EndOfFile",
171         "XmlReadState_Closed"
172     };
173
174     static const char unknown[] = "unknown";
175
176     switch (state)
177     {
178     case XmlReadState_Initial:
179     case XmlReadState_Interactive:
180     case XmlReadState_Error:
181     case XmlReadState_EndOfFile:
182     case XmlReadState_Closed:
183         return state_names[state];
184     default:
185         return unknown;
186     }
187 }
188
189 static const char *type_to_str(XmlNodeType type)
190 {
191     static const char* type_names[] = {
192         "XmlNodeType_None",
193         "XmlNodeType_Element",
194         "XmlNodeType_Attribute",
195         "XmlNodeType_Text",
196         "XmlNodeType_CDATA",
197         "", "",
198         "XmlNodeType_ProcessingInstruction",
199         "XmlNodeType_Comment",
200         "",
201         "XmlNodeType_DocumentType",
202         "", "",
203         "XmlNodeType_Whitespace",
204         "",
205         "XmlNodeType_EndElement",
206         "",
207         "XmlNodeType_XmlDeclaration"
208     };
209
210     static const char unknown[] = "unknown";
211
212     switch (type)
213     {
214     case XmlNodeType_None:
215     case XmlNodeType_Element:
216     case XmlNodeType_Attribute:
217     case XmlNodeType_Text:
218     case XmlNodeType_CDATA:
219     case XmlNodeType_ProcessingInstruction:
220     case XmlNodeType_Comment:
221     case XmlNodeType_DocumentType:
222     case XmlNodeType_Whitespace:
223     case XmlNodeType_EndElement:
224     case XmlNodeType_XmlDeclaration:
225         return type_names[type];
226     default:
227         return unknown;
228     }
229 }
230
231 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
232                                     XmlReadState exp_broken, int todo, int line)
233 {
234     XmlReadState state;
235     HRESULT hr;
236     int broken_state;
237
238     state = -1; /* invalid value */
239     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
240     ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
241
242     if (exp_broken == -1)
243         broken_state = 0;
244     else
245         broken_state = broken(exp_broken == state);
246
247     if (todo)
248     {
249     todo_wine
250         ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
251                                    state_to_str(expected), state_to_str(state));
252     }
253     else
254         ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
255                                    state_to_str(expected), state_to_str(state));
256 }
257
258 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
259
260 typedef struct _testinput
261 {
262     IUnknown IUnknown_iface;
263     LONG ref;
264 } testinput;
265
266 static inline testinput *impl_from_IUnknown(IUnknown *iface)
267 {
268     return CONTAINING_RECORD(iface, testinput, IUnknown_iface);
269 }
270
271 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
272 {
273     if (IsEqualGUID( riid, &IID_IUnknown ))
274     {
275         *ppvObj = iface;
276         IUnknown_AddRef(iface);
277         return S_OK;
278     }
279
280     input_iids.iids[input_iids.count++] = *riid;
281
282     *ppvObj = NULL;
283
284     return E_NOINTERFACE;
285 }
286
287 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
288 {
289     testinput *This = impl_from_IUnknown(iface);
290     return InterlockedIncrement(&This->ref);
291 }
292
293 static ULONG WINAPI testinput_Release(IUnknown *iface)
294 {
295     testinput *This = impl_from_IUnknown(iface);
296     LONG ref;
297
298     ref = InterlockedDecrement(&This->ref);
299     if (ref == 0)
300     {
301         HeapFree(GetProcessHeap(), 0, This);
302     }
303
304     return ref;
305 }
306
307 static const struct IUnknownVtbl testinput_vtbl =
308 {
309     testinput_QueryInterface,
310     testinput_AddRef,
311     testinput_Release
312 };
313
314 static HRESULT testinput_createinstance(void **ppObj)
315 {
316     testinput *input;
317
318     input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
319     if(!input) return E_OUTOFMEMORY;
320
321     input->IUnknown_iface.lpVtbl = &testinput_vtbl;
322     input->ref = 1;
323
324     *ppObj = &input->IUnknown_iface;
325
326     return S_OK;
327 }
328
329 static BOOL init_pointers(void)
330 {
331     /* don't free module here, it's to be unloaded on exit */
332     HMODULE mod = LoadLibraryA("xmllite.dll");
333
334     if (!mod)
335     {
336         win_skip("xmllite library not available\n");
337         return FALSE;
338     }
339
340 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
341     MAKEFUNC(CreateXmlReader);
342     MAKEFUNC(CreateXmlReaderInputWithEncodingName);
343 #undef MAKEFUNC
344
345     return TRUE;
346 }
347
348 static void test_reader_create(void)
349 {
350     HRESULT hr;
351     IXmlReader *reader;
352     IUnknown *input;
353     DtdProcessing dtd;
354     XmlNodeType nodetype;
355
356     /* crashes native */
357     if (0)
358     {
359         pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
360         pCreateXmlReader(NULL, (void**)&reader, NULL);
361     }
362
363     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
364     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
365
366     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
367
368     nodetype = XmlNodeType_Element;
369     hr = IXmlReader_GetNodeType(reader, &nodetype);
370     ok(hr == S_FALSE, "got %08x\n", hr);
371     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
372
373     dtd = 2;
374     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
375     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
376     ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
377
378     dtd = 2;
379     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
380     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
381
382     hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
383     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
384
385     /* Null input pointer, releases previous input */
386     hr = IXmlReader_SetInput(reader, NULL);
387     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
388
389     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
390
391     /* test input interface selection sequence */
392     hr = testinput_createinstance((void**)&input);
393     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
394
395     if (hr == S_OK)
396     {
397         input_iids.count = 0;
398         hr = IXmlReader_SetInput(reader, input);
399         ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
400         ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
401         IUnknown_Release(input);
402     }
403     IXmlReader_Release(reader);
404 }
405
406 static void test_readerinput(void)
407 {
408     IXmlReaderInput *reader_input;
409     IXmlReader *reader, *reader2;
410     IUnknown *obj, *input;
411     IStream *stream, *stream2;
412     XmlNodeType nodetype;
413     HRESULT hr;
414     LONG ref;
415
416     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
417     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
418     hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
419     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
420
421     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
422     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
423
424     ref = IStream_AddRef(stream);
425     ok(ref == 2, "Expected 2, got %d\n", ref);
426     IStream_Release(stream);
427     hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
428     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
429
430     hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
431     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
432
433     hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
434     ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
435
436     /* IXmlReaderInput grabs a stream reference */
437     ref = IStream_AddRef(stream);
438     ok(ref == 3, "Expected 3, got %d\n", ref);
439     IStream_Release(stream);
440
441     /* try ::SetInput() with valid IXmlReaderInput */
442     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
443     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
444
445     ref = IUnknown_AddRef(reader_input);
446     ok(ref == 2, "Expected 2, got %d\n", ref);
447     IUnknown_Release(reader_input);
448
449     hr = IXmlReader_SetInput(reader, reader_input);
450     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
451
452     test_read_state(reader, XmlReadState_Initial, -1, FALSE);
453
454     nodetype = XmlNodeType_Element;
455     hr = IXmlReader_GetNodeType(reader, &nodetype);
456     ok(hr == S_OK, "got %08x\n", hr);
457     ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
458
459     /* IXmlReader grabs a IXmlReaderInput reference */
460     ref = IUnknown_AddRef(reader_input);
461     ok(ref == 3, "Expected 3, got %d\n", ref);
462     IUnknown_Release(reader_input);
463
464     ref = IStream_AddRef(stream);
465     ok(ref == 4, "Expected 4, got %d\n", ref);
466     IStream_Release(stream);
467
468     /* reset input and check state */
469     hr = IXmlReader_SetInput(reader, NULL);
470     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
471
472     test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
473
474     IXmlReader_Release(reader);
475
476     ref = IStream_AddRef(stream);
477     ok(ref == 3, "Expected 3, got %d\n", ref);
478     IStream_Release(stream);
479
480     ref = IUnknown_AddRef(reader_input);
481     ok(ref == 2, "Expected 2, got %d\n", ref);
482     IUnknown_Release(reader_input);
483
484     /* IID_IXmlReaderInput */
485     /* it returns a kind of private undocumented vtable incompatible with IUnknown,
486        so it's not a COM interface actually.
487        Such query will be used only to check if input is really IXmlReaderInput */
488     obj = (IUnknown*)0xdeadbeef;
489     hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
490     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
491     ref = IUnknown_AddRef(reader_input);
492     ok(ref == 3, "Expected 3, got %d\n", ref);
493     IUnknown_Release(reader_input);
494
495     IUnknown_Release(reader_input);
496     IUnknown_Release(reader_input);
497     IStream_Release(stream);
498
499     /* test input interface selection sequence */
500     hr = testinput_createinstance((void**)&input);
501     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
502
503     input_iids.count = 0;
504     ref = IUnknown_AddRef(input);
505     ok(ref == 2, "Expected 2, got %d\n", ref);
506     IUnknown_Release(input);
507     hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
508     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
509     ok_iids(&input_iids, empty_seq, NULL, FALSE);
510     /* IXmlReaderInput stores stream interface as IUnknown */
511     ref = IUnknown_AddRef(input);
512     ok(ref == 3, "Expected 3, got %d\n", ref);
513     IUnknown_Release(input);
514
515     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
516     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
517
518     input_iids.count = 0;
519     ref = IUnknown_AddRef(reader_input);
520     ok(ref == 2, "Expected 2, got %d\n", ref);
521     IUnknown_Release(reader_input);
522     ref = IUnknown_AddRef(input);
523     ok(ref == 3, "Expected 3, got %d\n", ref);
524     IUnknown_Release(input);
525     hr = IXmlReader_SetInput(reader, reader_input);
526     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
527     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
528
529     test_read_state(reader, XmlReadState_Closed, -1, FALSE);
530
531     ref = IUnknown_AddRef(input);
532     ok(ref == 3, "Expected 3, got %d\n", ref);
533     IUnknown_Release(input);
534
535     ref = IUnknown_AddRef(reader_input);
536     ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
537           "Expected 3, got %d\n", ref);
538     IUnknown_Release(reader_input);
539     /* repeat another time, no check or caching here */
540     input_iids.count = 0;
541     hr = IXmlReader_SetInput(reader, reader_input);
542     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
543     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
544
545     /* another reader */
546     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
547     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
548
549     /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
550        ::SetInput() level, each time it's called */
551     input_iids.count = 0;
552     hr = IXmlReader_SetInput(reader2, reader_input);
553     ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
554     ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
555
556     IXmlReader_Release(reader2);
557     IXmlReader_Release(reader);
558
559     IUnknown_Release(reader_input);
560     IUnknown_Release(input);
561 }
562
563 static void test_reader_state(void)
564 {
565     IXmlReader *reader;
566     XmlNodeType nodetype;
567     HRESULT hr;
568
569     hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
570     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
571
572     /* invalid arguments */
573     hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
574     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
575
576     /* attempt to read on closed reader */
577     test_read_state(reader, XmlReadState_Closed, -1, 0);
578 if (0)
579 {
580     /* newer versions crash here, probably cause no input was set */
581     hr = IXmlReader_Read(reader, &nodetype);
582     ok(hr == S_FALSE, "got %08x\n", hr);
583 }
584     IXmlReader_Release(reader);
585 }
586
587 static void test_read_xmldeclaration(void)
588 {
589     IXmlReader *reader;
590     IStream *stream;
591     HRESULT hr;
592     XmlNodeType type;
593     UINT count = 0;
594
595     hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
596     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
597
598     /* position methods with Null args */
599     hr = IXmlReader_GetLineNumber(reader, NULL);
600     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
601
602     hr = IXmlReader_GetLinePosition(reader, NULL);
603     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
604
605     stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
606
607     hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
608     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
609
610     ok_pos(reader, 0, 0, -1, -1, FALSE);
611
612     type = -1;
613     hr = IXmlReader_Read(reader, &type);
614     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
615     ok(type == XmlNodeType_XmlDeclaration,
616                      "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
617     /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
618     ok_pos(reader, 1, 3, -1, 55, TRUE);
619     test_read_state(reader, XmlReadState_Interactive, -1, 0);
620
621     /* check attributes */
622     hr = IXmlReader_MoveToNextAttribute(reader);
623     todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
624     ok_pos(reader, 1, 7, -1, 55, TRUE);
625
626     hr = IXmlReader_MoveToFirstAttribute(reader);
627     todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
628     ok_pos(reader, 1, 7, -1, 55, TRUE);
629
630     hr = IXmlReader_GetAttributeCount(reader, &count);
631 todo_wine {
632     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
633     ok(count == 3, "Expected 3, got %d\n", count);
634 }
635     hr = IXmlReader_GetDepth(reader, &count);
636 todo_wine {
637     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
638     ok(count == 1, "Expected 1, got %d\n", count);
639 }
640
641     IStream_Release(stream);
642     IXmlReader_Release(reader);
643 }
644
645 START_TEST(reader)
646 {
647     HRESULT r;
648
649     r = CoInitialize( NULL );
650     ok( r == S_OK, "failed to init com\n");
651
652     if (!init_pointers())
653     {
654        CoUninitialize();
655        return;
656     }
657
658     test_reader_create();
659     test_readerinput();
660     test_reader_state();
661     test_read_xmldeclaration();
662
663     CoUninitialize();
664 }