[XMLLITE_WINETEST]: Sync with Wine 1.5.19.
[reactos.git] / rostests / winetests / xmllite / 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 const WCHAR *val;
595
596 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
597 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
598
599 /* position methods with Null args */
600 hr = IXmlReader_GetLineNumber(reader, NULL);
601 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
602
603 hr = IXmlReader_GetLinePosition(reader, NULL);
604 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
605
606 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
607
608 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
609 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
610
611 hr = IXmlReader_GetAttributeCount(reader, &count);
612 ok(hr == S_OK, "got %08x\n", hr);
613 ok(count == 0, "got %d\n", count);
614
615 /* try to move without attributes */
616 hr = IXmlReader_MoveToElement(reader);
617 ok(hr == S_FALSE, "got %08x\n", hr);
618
619 hr = IXmlReader_MoveToNextAttribute(reader);
620 ok(hr == S_FALSE, "got %08x\n", hr);
621
622 hr = IXmlReader_MoveToFirstAttribute(reader);
623 ok(hr == S_FALSE, "got %08x\n", hr);
624
625 ok_pos(reader, 0, 0, -1, -1, FALSE);
626
627 type = -1;
628 hr = IXmlReader_Read(reader, &type);
629 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
630 ok(type == XmlNodeType_XmlDeclaration,
631 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
632 /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
633 ok_pos(reader, 1, 3, -1, 55, TRUE);
634 test_read_state(reader, XmlReadState_Interactive, -1, 0);
635
636 hr = IXmlReader_GetValue(reader, &val, NULL);
637 todo_wine
638 ok(hr == S_OK, "got %08x\n", hr);
639 if (hr == S_OK)
640 ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
641
642 /* check attributes */
643 hr = IXmlReader_MoveToNextAttribute(reader);
644 ok(hr == S_OK, "got %08x\n", hr);
645
646 type = XmlNodeType_None;
647 hr = IXmlReader_GetNodeType(reader, &type);
648 ok(hr == S_OK, "got %08x\n", hr);
649 ok(type == XmlNodeType_Attribute, "got %d\n", type);
650
651 ok_pos(reader, 1, 7, -1, 55, TRUE);
652
653 /* try to move from last attribute */
654 hr = IXmlReader_MoveToNextAttribute(reader);
655 ok(hr == S_OK, "got %08x\n", hr);
656 hr = IXmlReader_MoveToNextAttribute(reader);
657 ok(hr == S_OK, "got %08x\n", hr);
658 hr = IXmlReader_MoveToNextAttribute(reader);
659 ok(hr == S_FALSE, "got %08x\n", hr);
660
661 type = XmlNodeType_None;
662 hr = IXmlReader_GetNodeType(reader, &type);
663 ok(hr == S_OK, "got %08x\n", hr);
664 ok(type == XmlNodeType_Attribute, "got %d\n", type);
665
666 hr = IXmlReader_MoveToFirstAttribute(reader);
667 ok(hr == S_OK, "got %08x\n", hr);
668 ok_pos(reader, 1, 7, -1, 55, TRUE);
669
670 hr = IXmlReader_GetAttributeCount(reader, NULL);
671 ok(hr == E_INVALIDARG, "got %08x\n", hr);
672
673 hr = IXmlReader_GetAttributeCount(reader, &count);
674 ok(hr == S_OK, "got %08x\n", hr);
675 ok(count == 3, "Expected 3, got %d\n", count);
676
677 hr = IXmlReader_GetDepth(reader, &count);
678 todo_wine {
679 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
680 ok(count == 1, "Expected 1, got %d\n", count);
681 }
682
683 hr = IXmlReader_MoveToElement(reader);
684 ok(hr == S_OK, "got %08x\n", hr);
685
686 type = XmlNodeType_None;
687 hr = IXmlReader_GetNodeType(reader, &type);
688 ok(hr == S_OK, "got %08x\n", hr);
689 ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type);
690
691 IStream_Release(stream);
692 IXmlReader_Release(reader);
693 }
694
695 START_TEST(reader)
696 {
697 HRESULT r;
698
699 r = CoInitialize( NULL );
700 ok( r == S_OK, "failed to init com\n");
701
702 if (!init_pointers())
703 {
704 CoUninitialize();
705 return;
706 }
707
708 test_reader_create();
709 test_readerinput();
710 test_reader_state();
711 test_read_xmldeclaration();
712
713 CoUninitialize();
714 }