44e8e59268f917a23ec8e5e738b0385e63e69a0d
[reactos.git] / rostests / winetests / xmllite / 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 WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #define COBJMACROS
26 #define CONST_VTABLE
27
28 //#include <stdarg.h>
29 #include <stdio.h>
30
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnls.h>
34 #include <initguid.h>
35 #include <ole2.h>
36 #include <xmllite.h>
37 #include <wine/test.h>
38
39 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
40
41 static WCHAR *a2w(const char *str)
42 {
43 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
44 WCHAR *ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
45 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
46 return ret;
47 }
48
49 static void free_str(WCHAR *str)
50 {
51 HeapFree(GetProcessHeap(), 0, str);
52 }
53
54 static const char xmldecl_full[] = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
55 static const char xmldecl_short[] = "<?xml version=\"1.0\"?><RegistrationInfo/>";
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, BOOL todo, int _line_)
80 {
81 UINT l, p;
82 HRESULT hr;
83 BOOL 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 = FALSE;
92 else
93 broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
94 (pos_broken == -1 ? pos : pos_broken) == p);
95
96 todo_wine_if (todo)
97 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
98 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
99 }
100 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
101
102 typedef struct input_iids_t {
103 IID iids[10];
104 int count;
105 } input_iids_t;
106
107 static const IID *setinput_full[] = {
108 &IID_IXmlReaderInput,
109 &IID_IStream,
110 &IID_ISequentialStream,
111 NULL
112 };
113
114 /* this applies to early xmllite versions */
115 static const IID *setinput_full_old[] = {
116 &IID_IXmlReaderInput,
117 &IID_ISequentialStream,
118 &IID_IStream,
119 NULL
120 };
121
122 /* after ::SetInput(IXmlReaderInput*) */
123 static const IID *setinput_readerinput[] = {
124 &IID_IStream,
125 &IID_ISequentialStream,
126 NULL
127 };
128
129 static const IID *empty_seq[] = {
130 NULL
131 };
132
133 static input_iids_t input_iids;
134
135 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, BOOL todo, int line)
136 {
137 int i = 0, size = 0;
138
139 while (expected[i++]) size++;
140
141 todo_wine_if (todo)
142 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
143
144 if (iids->count != size) return;
145
146 for (i = 0; i < size; i++) {
147 ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
148 (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
149 "Wrong IID(%d), got %s\n", i, wine_dbgstr_guid(&iids->iids[i]));
150 }
151 }
152 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
153
154 static const char *state_to_str(XmlReadState state)
155 {
156 static const char* state_names[] = {
157 "XmlReadState_Initial",
158 "XmlReadState_Interactive",
159 "XmlReadState_Error",
160 "XmlReadState_EndOfFile",
161 "XmlReadState_Closed"
162 };
163
164 static const char unknown[] = "unknown";
165
166 switch (state)
167 {
168 case XmlReadState_Initial:
169 case XmlReadState_Interactive:
170 case XmlReadState_Error:
171 case XmlReadState_EndOfFile:
172 case XmlReadState_Closed:
173 return state_names[state];
174 default:
175 return unknown;
176 }
177 }
178
179 static const char *type_to_str(XmlNodeType type)
180 {
181 static const char* type_names[] = {
182 "XmlNodeType_None",
183 "XmlNodeType_Element",
184 "XmlNodeType_Attribute",
185 "XmlNodeType_Text",
186 "XmlNodeType_CDATA",
187 "", "",
188 "XmlNodeType_ProcessingInstruction",
189 "XmlNodeType_Comment",
190 "",
191 "XmlNodeType_DocumentType",
192 "", "",
193 "XmlNodeType_Whitespace",
194 "",
195 "XmlNodeType_EndElement",
196 "",
197 "XmlNodeType_XmlDeclaration"
198 };
199
200 static const char unknown[] = "unknown";
201
202 switch (type)
203 {
204 case XmlNodeType_None:
205 case XmlNodeType_Element:
206 case XmlNodeType_Attribute:
207 case XmlNodeType_Text:
208 case XmlNodeType_CDATA:
209 case XmlNodeType_ProcessingInstruction:
210 case XmlNodeType_Comment:
211 case XmlNodeType_DocumentType:
212 case XmlNodeType_Whitespace:
213 case XmlNodeType_EndElement:
214 case XmlNodeType_XmlDeclaration:
215 return type_names[type];
216 default:
217 return unknown;
218 }
219 }
220
221 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
222 XmlReadState exp_broken, BOOL todo, int line)
223 {
224 LONG_PTR state;
225 HRESULT hr;
226 BOOL broken_state;
227
228 state = -1; /* invalid value */
229 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, &state);
230 ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
231
232 if (exp_broken == -1)
233 broken_state = FALSE;
234 else
235 broken_state = broken(exp_broken == state);
236
237 todo_wine_if (todo)
238 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
239 state_to_str(expected), state_to_str(state));
240 }
241
242 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
243
244 typedef struct _testinput
245 {
246 IUnknown IUnknown_iface;
247 LONG ref;
248 } testinput;
249
250 static inline testinput *impl_from_IUnknown(IUnknown *iface)
251 {
252 return CONTAINING_RECORD(iface, testinput, IUnknown_iface);
253 }
254
255 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
256 {
257 if (IsEqualGUID( riid, &IID_IUnknown ))
258 {
259 *ppvObj = iface;
260 IUnknown_AddRef(iface);
261 return S_OK;
262 }
263
264 input_iids.iids[input_iids.count++] = *riid;
265
266 *ppvObj = NULL;
267
268 return E_NOINTERFACE;
269 }
270
271 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
272 {
273 testinput *This = impl_from_IUnknown(iface);
274 return InterlockedIncrement(&This->ref);
275 }
276
277 static ULONG WINAPI testinput_Release(IUnknown *iface)
278 {
279 testinput *This = impl_from_IUnknown(iface);
280 LONG ref;
281
282 ref = InterlockedDecrement(&This->ref);
283 if (ref == 0)
284 {
285 HeapFree(GetProcessHeap(), 0, This);
286 }
287
288 return ref;
289 }
290
291 static const struct IUnknownVtbl testinput_vtbl =
292 {
293 testinput_QueryInterface,
294 testinput_AddRef,
295 testinput_Release
296 };
297
298 static HRESULT testinput_createinstance(void **ppObj)
299 {
300 testinput *input;
301
302 input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
303 if(!input) return E_OUTOFMEMORY;
304
305 input->IUnknown_iface.lpVtbl = &testinput_vtbl;
306 input->ref = 1;
307
308 *ppObj = &input->IUnknown_iface;
309
310 return S_OK;
311 }
312
313 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
314 {
315 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
316 {
317 *obj = iface;
318 return S_OK;
319 }
320
321 *obj = NULL;
322 return E_NOINTERFACE;
323 }
324
325 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
326 {
327 return 2;
328 }
329
330 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
331 {
332 return 1;
333 }
334
335 static int stream_readcall;
336
337 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
338 {
339 static const char xml[] = "<!-- comment -->";
340
341 if (stream_readcall++)
342 {
343 *pread = 0;
344 return E_PENDING;
345 }
346
347 *pread = sizeof(xml) / 2;
348 memcpy(pv, xml, *pread);
349 return S_OK;
350 }
351
352 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
353 {
354 ok(0, "unexpected call\n");
355 return E_NOTIMPL;
356 }
357
358 static const ISequentialStreamVtbl teststreamvtbl =
359 {
360 teststream_QueryInterface,
361 teststream_AddRef,
362 teststream_Release,
363 teststream_Read,
364 teststream_Write
365 };
366
367 static HRESULT WINAPI resolver_QI(IXmlResolver *iface, REFIID riid, void **obj)
368 {
369 ok(0, "unexpected call, riid %s\n", wine_dbgstr_guid(riid));
370
371 if (IsEqualIID(riid, &IID_IXmlResolver) || IsEqualIID(riid, &IID_IUnknown))
372 {
373 *obj = iface;
374 IXmlResolver_AddRef(iface);
375 return S_OK;
376 }
377
378 *obj = NULL;
379 return E_NOINTERFACE;
380 }
381
382 static ULONG WINAPI resolver_AddRef(IXmlResolver *iface)
383 {
384 return 2;
385 }
386
387 static ULONG WINAPI resolver_Release(IXmlResolver *iface)
388 {
389 return 1;
390 }
391
392 static HRESULT WINAPI resolver_ResolveUri(IXmlResolver *iface, const WCHAR *base_uri,
393 const WCHAR *public_id, const WCHAR *system_id, IUnknown **input)
394 {
395 ok(0, "unexpected call\n");
396 return E_NOTIMPL;
397 }
398
399 static const IXmlResolverVtbl resolvervtbl =
400 {
401 resolver_QI,
402 resolver_AddRef,
403 resolver_Release,
404 resolver_ResolveUri
405 };
406
407 static IXmlResolver testresolver = { &resolvervtbl };
408
409 static void test_reader_create(void)
410 {
411 IXmlResolver *resolver;
412 HRESULT hr;
413 IXmlReader *reader;
414 IUnknown *input;
415 DtdProcessing dtd;
416 XmlNodeType nodetype;
417
418 /* crashes native */
419 if (0)
420 {
421 CreateXmlReader(&IID_IXmlReader, NULL, NULL);
422 CreateXmlReader(NULL, (void**)&reader, NULL);
423 }
424
425 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
426 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
427
428 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
429
430 nodetype = XmlNodeType_Element;
431 hr = IXmlReader_GetNodeType(reader, &nodetype);
432 ok(hr == S_FALSE, "got %08x\n", hr);
433 ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
434
435 resolver = (void*)0xdeadbeef;
436 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_XmlResolver, (LONG_PTR*)&resolver);
437 ok(hr == S_OK, "got 0x%08x\n", hr);
438 ok(resolver == NULL, "got %p\n", resolver);
439
440 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_XmlResolver, 0);
441 ok(hr == S_OK, "got 0x%08x\n", hr);
442
443 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_XmlResolver, (LONG_PTR)&testresolver);
444 ok(hr == S_OK, "got 0x%08x\n", hr);
445
446 resolver = NULL;
447 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_XmlResolver, (LONG_PTR*)&resolver);
448 ok(hr == S_OK, "got 0x%08x\n", hr);
449 ok(resolver == &testresolver, "got %p\n", resolver);
450 IXmlResolver_Release(resolver);
451
452 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_XmlResolver, 0);
453 ok(hr == S_OK, "got 0x%08x\n", hr);
454
455 dtd = 2;
456 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_DtdProcessing, (LONG_PTR*)&dtd);
457 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
458 ok(dtd == DtdProcessing_Prohibit, "got %d\n", dtd);
459
460 dtd = 2;
461 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, dtd);
462 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
463
464 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, -1);
465 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
466
467 /* Null input pointer, releases previous input */
468 hr = IXmlReader_SetInput(reader, NULL);
469 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
470
471 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
472
473 /* test input interface selection sequence */
474 hr = testinput_createinstance((void**)&input);
475 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
476
477 if (hr == S_OK)
478 {
479 input_iids.count = 0;
480 hr = IXmlReader_SetInput(reader, input);
481 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
482 ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
483 IUnknown_Release(input);
484 }
485 IXmlReader_Release(reader);
486 }
487
488 static void test_readerinput(void)
489 {
490 IXmlReaderInput *reader_input;
491 IXmlReader *reader, *reader2;
492 IUnknown *obj, *input;
493 IStream *stream, *stream2;
494 XmlNodeType nodetype;
495 HRESULT hr;
496 LONG ref;
497
498 hr = CreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
499 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
500 hr = CreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
501 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
502
503 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
504 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
505
506 ref = IStream_AddRef(stream);
507 ok(ref == 2, "Expected 2, got %d\n", ref);
508 IStream_Release(stream);
509 hr = CreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
510 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
511
512 hr = IUnknown_QueryInterface(reader_input, &IID_IStream, (void**)&stream2);
513 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
514
515 hr = IUnknown_QueryInterface(reader_input, &IID_ISequentialStream, (void**)&stream2);
516 ok(hr == E_NOINTERFACE, "Expected S_OK, got %08x\n", hr);
517
518 /* IXmlReaderInput grabs a stream reference */
519 ref = IStream_AddRef(stream);
520 ok(ref == 3, "Expected 3, got %d\n", ref);
521 IStream_Release(stream);
522
523 /* try ::SetInput() with valid IXmlReaderInput */
524 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
525 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
526
527 ref = IUnknown_AddRef(reader_input);
528 ok(ref == 2, "Expected 2, got %d\n", ref);
529 IUnknown_Release(reader_input);
530
531 hr = IXmlReader_SetInput(reader, reader_input);
532 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
533
534 test_read_state(reader, XmlReadState_Initial, -1, FALSE);
535
536 nodetype = XmlNodeType_Element;
537 hr = IXmlReader_GetNodeType(reader, &nodetype);
538 ok(hr == S_OK, "got %08x\n", hr);
539 ok(nodetype == XmlNodeType_None, "got %d\n", nodetype);
540
541 /* IXmlReader grabs a IXmlReaderInput reference */
542 ref = IUnknown_AddRef(reader_input);
543 ok(ref == 3, "Expected 3, got %d\n", ref);
544 IUnknown_Release(reader_input);
545
546 ref = IStream_AddRef(stream);
547 ok(ref == 4, "Expected 4, got %d\n", ref);
548 IStream_Release(stream);
549
550 /* reset input and check state */
551 hr = IXmlReader_SetInput(reader, NULL);
552 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
553
554 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
555
556 IXmlReader_Release(reader);
557
558 ref = IStream_AddRef(stream);
559 ok(ref == 3, "Expected 3, got %d\n", ref);
560 IStream_Release(stream);
561
562 ref = IUnknown_AddRef(reader_input);
563 ok(ref == 2, "Expected 2, got %d\n", ref);
564 IUnknown_Release(reader_input);
565
566 /* IID_IXmlReaderInput */
567 /* it returns a kind of private undocumented vtable incompatible with IUnknown,
568 so it's not a COM interface actually.
569 Such query will be used only to check if input is really IXmlReaderInput */
570 obj = (IUnknown*)0xdeadbeef;
571 hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
572 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
573 ref = IUnknown_AddRef(reader_input);
574 ok(ref == 3, "Expected 3, got %d\n", ref);
575 IUnknown_Release(reader_input);
576
577 IUnknown_Release(reader_input);
578 IUnknown_Release(reader_input);
579 IStream_Release(stream);
580
581 /* test input interface selection sequence */
582 input = NULL;
583 hr = testinput_createinstance((void**)&input);
584 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
585
586 input_iids.count = 0;
587 ref = IUnknown_AddRef(input);
588 ok(ref == 2, "Expected 2, got %d\n", ref);
589 IUnknown_Release(input);
590 hr = CreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
591 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
592 ok_iids(&input_iids, empty_seq, NULL, FALSE);
593 /* IXmlReaderInput stores stream interface as IUnknown */
594 ref = IUnknown_AddRef(input);
595 ok(ref == 3, "Expected 3, got %d\n", ref);
596 IUnknown_Release(input);
597
598 hr = CreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
599 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
600
601 input_iids.count = 0;
602 ref = IUnknown_AddRef(reader_input);
603 ok(ref == 2, "Expected 2, got %d\n", ref);
604 IUnknown_Release(reader_input);
605 ref = IUnknown_AddRef(input);
606 ok(ref == 3, "Expected 3, got %d\n", ref);
607 IUnknown_Release(input);
608 hr = IXmlReader_SetInput(reader, reader_input);
609 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
610 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
611
612 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
613
614 ref = IUnknown_AddRef(input);
615 ok(ref == 3, "Expected 3, got %d\n", ref);
616 IUnknown_Release(input);
617
618 ref = IUnknown_AddRef(reader_input);
619 ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
620 "Expected 3, got %d\n", ref);
621 IUnknown_Release(reader_input);
622 /* repeat another time, no check or caching here */
623 input_iids.count = 0;
624 hr = IXmlReader_SetInput(reader, reader_input);
625 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
626 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
627
628 /* another reader */
629 hr = CreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
630 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
631
632 /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
633 ::SetInput() level, each time it's called */
634 input_iids.count = 0;
635 hr = IXmlReader_SetInput(reader2, reader_input);
636 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
637 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
638
639 IXmlReader_Release(reader2);
640 IXmlReader_Release(reader);
641
642 IUnknown_Release(reader_input);
643 IUnknown_Release(input);
644 }
645
646 static void test_reader_state(void)
647 {
648 IXmlReader *reader;
649 XmlNodeType nodetype;
650 HRESULT hr;
651
652 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
653 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
654
655 /* invalid arguments */
656 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
657 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
658
659 /* attempt to read on closed reader */
660 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
661 if (0)
662 {
663 /* newer versions crash here, probably cause no input was set */
664 hr = IXmlReader_Read(reader, &nodetype);
665 ok(hr == S_FALSE, "got %08x\n", hr);
666 }
667 IXmlReader_Release(reader);
668 }
669
670 static void test_read_xmldeclaration(void)
671 {
672 static const WCHAR xmlW[] = {'x','m','l',0};
673 static const WCHAR RegistrationInfoW[] = {'R','e','g','i','s','t','r','a','t','i','o','n','I','n','f','o',0};
674 static const struct
675 {
676 WCHAR name[12];
677 WCHAR val[12];
678 } name_val[] =
679 {
680 { {'v','e','r','s','i','o','n',0}, {'1','.','0',0} },
681 { {'e','n','c','o','d','i','n','g',0}, {'U','T','F','-','8',0} },
682 { {'s','t','a','n','d','a','l','o','n','e',0}, {'y','e','s',0} }
683 };
684 IXmlReader *reader;
685 IStream *stream;
686 HRESULT hr;
687 XmlNodeType type;
688 UINT count = 0, len, i;
689 BOOL ret;
690 const WCHAR *val;
691
692 hr = CreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
693 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
694
695 /* position methods with Null args */
696 hr = IXmlReader_GetLineNumber(reader, NULL);
697 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
698
699 hr = IXmlReader_GetLinePosition(reader, NULL);
700 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
701
702 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
703
704 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
705 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
706
707 hr = IXmlReader_GetAttributeCount(reader, &count);
708 ok(hr == S_OK, "got %08x\n", hr);
709 ok(count == 0, "got %d\n", count);
710
711 /* try to move without attributes */
712 hr = IXmlReader_MoveToElement(reader);
713 ok(hr == S_FALSE, "got %08x\n", hr);
714
715 hr = IXmlReader_MoveToNextAttribute(reader);
716 ok(hr == S_FALSE, "got %08x\n", hr);
717
718 hr = IXmlReader_MoveToFirstAttribute(reader);
719 ok(hr == S_FALSE, "got %08x\n", hr);
720
721 ok_pos(reader, 0, 0, -1, -1, FALSE);
722
723 type = -1;
724 hr = IXmlReader_Read(reader, &type);
725 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
726 ok(type == XmlNodeType_XmlDeclaration,
727 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
728 /* new version 1.2.x and 1.3.x properly update position for <?xml ?> */
729 ok_pos(reader, 1, 3, -1, 55, TRUE);
730 test_read_state(reader, XmlReadState_Interactive, -1, FALSE);
731
732 hr = IXmlReader_GetValue(reader, &val, NULL);
733 ok(hr == S_OK, "got %08x\n", hr);
734 ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
735
736 /* check attributes */
737 hr = IXmlReader_MoveToNextAttribute(reader);
738 ok(hr == S_OK, "got %08x\n", hr);
739
740 type = XmlNodeType_None;
741 hr = IXmlReader_GetNodeType(reader, &type);
742 ok(hr == S_OK, "got %08x\n", hr);
743 ok(type == XmlNodeType_Attribute, "got %d\n", type);
744
745 ok_pos(reader, 1, 7, -1, 55, TRUE);
746
747 /* try to move from last attribute */
748 hr = IXmlReader_MoveToNextAttribute(reader);
749 ok(hr == S_OK, "got %08x\n", hr);
750 hr = IXmlReader_MoveToNextAttribute(reader);
751 ok(hr == S_OK, "got %08x\n", hr);
752 hr = IXmlReader_MoveToNextAttribute(reader);
753 ok(hr == S_FALSE, "got %08x\n", hr);
754
755 type = XmlNodeType_None;
756 hr = IXmlReader_GetNodeType(reader, &type);
757 ok(hr == S_OK, "got %08x\n", hr);
758 ok(type == XmlNodeType_Attribute, "got %d\n", type);
759
760 hr = IXmlReader_MoveToFirstAttribute(reader);
761 ok(hr == S_OK, "got %08x\n", hr);
762 ok_pos(reader, 1, 7, -1, 55, TRUE);
763
764 hr = IXmlReader_GetAttributeCount(reader, NULL);
765 ok(hr == E_INVALIDARG, "got %08x\n", hr);
766
767 hr = IXmlReader_GetAttributeCount(reader, &count);
768 ok(hr == S_OK, "got %08x\n", hr);
769 ok(count == 3, "Expected 3, got %d\n", count);
770
771 for (i = 0; i < count; i++)
772 {
773 len = 0;
774 hr = IXmlReader_GetLocalName(reader, &val, &len);
775 ok(hr == S_OK, "got %08x\n", hr);
776 ok(len == lstrlenW(name_val[i].name), "expected %u, got %u\n", lstrlenW(name_val[i].name), len);
777 ok(!lstrcmpW(name_val[i].name, val), "expected %s, got %s\n", wine_dbgstr_w(name_val[i].name), wine_dbgstr_w(val));
778
779 len = 0;
780 hr = IXmlReader_GetValue(reader, &val, &len);
781 ok(hr == S_OK, "got %08x\n", hr);
782 ok(len == lstrlenW(name_val[i].val), "expected %u, got %u\n", lstrlenW(name_val[i].val), len);
783 ok(!lstrcmpW(name_val[i].val, val), "expected %s, got %s\n", wine_dbgstr_w(name_val[i].val), wine_dbgstr_w(val));
784
785 hr = IXmlReader_MoveToNextAttribute(reader);
786 ok(hr == ((i < count - 1) ? S_OK : S_FALSE), "got %08x\n", hr);
787 }
788
789 hr = IXmlReader_GetDepth(reader, &count);
790 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
791 ok(count == 1, "Expected 1, got %d\n", count);
792
793 hr = IXmlReader_MoveToElement(reader);
794 ok(hr == S_OK, "got %08x\n", hr);
795
796 type = XmlNodeType_None;
797 hr = IXmlReader_GetNodeType(reader, &type);
798 ok(hr == S_OK, "got %08x\n", hr);
799 ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type);
800
801 type = XmlNodeType_XmlDeclaration;
802 hr = IXmlReader_Read(reader, &type);
803 /* newer versions return syntax error here cause document is incomplete,
804 it makes more sense than invalid char error */
805 todo_wine {
806 ok(hr == WC_E_SYNTAX || broken(hr == WC_E_XMLCHARACTER), "got 0x%08x\n", hr);
807 ok(type == XmlNodeType_None, "got %d\n", type);
808 }
809 IStream_Release(stream);
810
811 /* test short variant */
812 stream = create_stream_on_data(xmldecl_short, sizeof(xmldecl_short));
813
814 hr = IXmlReader_SetInput(reader, (IUnknown *)stream);
815 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
816
817 type = -1;
818 hr = IXmlReader_Read(reader, &type);
819 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
820 ok(type == XmlNodeType_XmlDeclaration, "expected XmlDeclaration, got %s\n", type_to_str(type));
821 ok_pos(reader, 1, 3, 1, 21, TRUE);
822 test_read_state(reader, XmlReadState_Interactive, -1, TRUE);
823
824 hr = IXmlReader_GetAttributeCount(reader, &count);
825 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
826 ok(count == 1, "expected 1, got %d\n", count);
827
828 ret = IXmlReader_IsEmptyElement(reader);
829 ok(!ret, "element should not be empty\n");
830
831 hr = IXmlReader_GetValue(reader, &val, NULL);
832 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
833 ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
834
835 hr = IXmlReader_GetLocalName(reader, &val, NULL);
836 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
837 todo_wine
838 ok(!lstrcmpW(val, xmlW), "got %s\n", wine_dbgstr_w(val));
839
840 /* check attributes */
841 hr = IXmlReader_MoveToNextAttribute(reader);
842 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
843
844 type = -1;
845 hr = IXmlReader_GetNodeType(reader, &type);
846 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
847 ok(type == XmlNodeType_Attribute, "got %d\n", type);
848 ok_pos(reader, 1, 7, 1, 21, TRUE);
849
850 /* try to move from last attribute */
851 hr = IXmlReader_MoveToNextAttribute(reader);
852 ok(hr == S_FALSE, "expected S_FALSE, got %08x\n", hr);
853
854 type = -1;
855 hr = IXmlReader_Read(reader, &type);
856 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
857 ok(type == XmlNodeType_Element, "expected Element, got %s\n", type_to_str(type));
858 ok_pos(reader, 1, 23, 1, 40, TRUE);
859 test_read_state(reader, XmlReadState_Interactive, -1, TRUE);
860
861 hr = IXmlReader_GetAttributeCount(reader, &count);
862 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
863 ok(count == 0, "expected 0, got %d\n", count);
864
865 ret = IXmlReader_IsEmptyElement(reader);
866 ok(ret, "element should be empty\n");
867
868 hr = IXmlReader_GetValue(reader, &val, NULL);
869 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
870 todo_wine
871 ok(*val == 0, "got %s\n", wine_dbgstr_w(val));
872
873 hr = IXmlReader_GetLocalName(reader, &val, NULL);
874 ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
875 ok(!lstrcmpW(val, RegistrationInfoW), "got %s\n", wine_dbgstr_w(val));
876
877 type = -1;
878 hr = IXmlReader_Read(reader, &type);
879 todo_wine
880 ok(hr == WC_E_SYNTAX || hr == WC_E_XMLCHARACTER /* XP */, "expected WC_E_SYNTAX, got %08x\n", hr);
881 todo_wine
882 ok(type == XmlNodeType_None, "expected None, got %s\n", type_to_str(type));
883 ok_pos(reader, 1, 41, -1, -1, TRUE);
884 test_read_state(reader, XmlReadState_Error, -1, TRUE);
885
886 IStream_Release(stream);
887 IXmlReader_Release(reader);
888 }
889
890 struct test_entry {
891 const char *xml;
892 const char *name;
893 const char *value;
894 HRESULT hr;
895 HRESULT hr_broken; /* this is set to older version results */
896 BOOL todo;
897 };
898
899 static struct test_entry comment_tests[] = {
900 { "<!-- comment -->", "", " comment ", S_OK },
901 { "<!-- - comment-->", "", " - comment", S_OK },
902 { "<!-- -- comment-->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
903 { "<!-- -- comment--->", NULL, NULL, WC_E_COMMENT, WC_E_GREATERTHAN },
904 { NULL }
905 };
906
907 static void test_read_comment(void)
908 {
909 struct test_entry *test = comment_tests;
910 IXmlReader *reader;
911 HRESULT hr;
912
913 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
914 ok(hr == S_OK, "S_OK, got %08x\n", hr);
915
916 while (test->xml)
917 {
918 XmlNodeType type;
919 IStream *stream;
920
921 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
922 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
923 ok(hr == S_OK, "got %08x\n", hr);
924
925 type = XmlNodeType_None;
926 hr = IXmlReader_Read(reader, &type);
927 if (test->hr_broken)
928 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
929 else
930 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
931 if (hr == S_OK)
932 {
933 const WCHAR *str;
934 WCHAR *str_exp;
935 UINT len;
936
937 ok(type == XmlNodeType_Comment, "got %d for %s\n", type, test->xml);
938
939 len = 1;
940 str = NULL;
941 hr = IXmlReader_GetLocalName(reader, &str, &len);
942 ok(hr == S_OK, "got 0x%08x\n", hr);
943 ok(len == strlen(test->name), "got %u\n", len);
944 str_exp = a2w(test->name);
945 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
946 free_str(str_exp);
947
948 len = 1;
949 str = NULL;
950 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
951 ok(hr == S_OK, "got 0x%08x\n", hr);
952 ok(len == strlen(test->name), "got %u\n", len);
953 str_exp = a2w(test->name);
954 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
955 free_str(str_exp);
956
957 /* value */
958 len = 1;
959 str = NULL;
960 hr = IXmlReader_GetValue(reader, &str, &len);
961 ok(hr == S_OK, "got 0x%08x\n", hr);
962 ok(len == strlen(test->value), "got %u\n", len);
963 str_exp = a2w(test->value);
964 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
965 free_str(str_exp);
966 }
967
968 IStream_Release(stream);
969 test++;
970 }
971
972 IXmlReader_Release(reader);
973 }
974
975 static struct test_entry pi_tests[] = {
976 { "<?pi?>", "pi", "", S_OK },
977 { "<?pi ?>", "pi", "", S_OK },
978 { "<?pi ?>", "pi", "", S_OK },
979 { "<?pi pi data?>", "pi", "pi data", S_OK },
980 { "<?pi pi data ?>", "pi", "pi data ", S_OK },
981 { "<?pi data ?>", "pi", "data ", S_OK },
982 { "<?pi:pi?>", NULL, NULL, NC_E_NAMECOLON, WC_E_NAMECHARACTER },
983 { "<?:pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
984 { "<?-pi ?>", NULL, NULL, WC_E_PI, WC_E_NAMECHARACTER },
985 { "<?xml-stylesheet ?>", "xml-stylesheet", "", S_OK },
986 { NULL }
987 };
988
989 static void test_read_pi(void)
990 {
991 struct test_entry *test = pi_tests;
992 IXmlReader *reader;
993 HRESULT hr;
994
995 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
996 ok(hr == S_OK, "S_OK, got %08x\n", hr);
997
998 while (test->xml)
999 {
1000 XmlNodeType type;
1001 IStream *stream;
1002
1003 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1004 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1005 ok(hr == S_OK, "got %08x\n", hr);
1006
1007 type = XmlNodeType_None;
1008 hr = IXmlReader_Read(reader, &type);
1009 if (test->hr_broken)
1010 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1011 else
1012 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1013 if (hr == S_OK)
1014 {
1015 const WCHAR *str;
1016 WCHAR *str_exp;
1017 UINT len;
1018
1019 ok(type == XmlNodeType_ProcessingInstruction, "got %d for %s\n", type, test->xml);
1020
1021 len = 0;
1022 str = NULL;
1023 hr = IXmlReader_GetLocalName(reader, &str, &len);
1024 ok(hr == S_OK, "got 0x%08x\n", hr);
1025 ok(len == strlen(test->name), "got %u\n", len);
1026 str_exp = a2w(test->name);
1027 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1028 free_str(str_exp);
1029
1030 len = 0;
1031 str = NULL;
1032 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1033 ok(hr == S_OK, "got 0x%08x\n", hr);
1034 ok(len == strlen(test->name), "got %u\n", len);
1035 str_exp = a2w(test->name);
1036 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1037 free_str(str_exp);
1038
1039 /* value */
1040 len = !strlen(test->value);
1041 str = NULL;
1042 hr = IXmlReader_GetValue(reader, &str, &len);
1043 ok(hr == S_OK, "got 0x%08x\n", hr);
1044 ok(len == strlen(test->value), "got %u\n", len);
1045 str_exp = a2w(test->value);
1046 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1047 free_str(str_exp);
1048 }
1049
1050 IStream_Release(stream);
1051 test++;
1052 }
1053
1054 IXmlReader_Release(reader);
1055 }
1056
1057 struct nodes_test {
1058 const char *xml;
1059 XmlNodeType types[20];
1060 };
1061
1062 static const char misc_test_xml[] =
1063 "<!-- comment1 -->"
1064 "<!-- comment2 -->"
1065 "<?pi1 pi1body ?>"
1066 "<!-- comment3 -->"
1067 " \t \r \n"
1068 "<!-- comment4 -->"
1069 "<a>"
1070 "\r\n\t"
1071 "<b/>"
1072 "text"
1073 "<!-- comment -->"
1074 "text2"
1075 "<?pi pibody ?>"
1076 "\r\n"
1077 "</a>"
1078 ;
1079
1080 static struct nodes_test misc_test = {
1081 misc_test_xml,
1082 {
1083 XmlNodeType_Comment,
1084 XmlNodeType_Comment,
1085 XmlNodeType_ProcessingInstruction,
1086 XmlNodeType_Comment,
1087 XmlNodeType_Whitespace,
1088 XmlNodeType_Comment,
1089 XmlNodeType_Element,
1090 XmlNodeType_Whitespace,
1091 XmlNodeType_Element,
1092 XmlNodeType_Text,
1093 XmlNodeType_Comment,
1094 XmlNodeType_Text,
1095 XmlNodeType_ProcessingInstruction,
1096 XmlNodeType_Whitespace,
1097 XmlNodeType_EndElement,
1098 XmlNodeType_None
1099 }
1100 };
1101
1102 static void test_read_full(void)
1103 {
1104 struct nodes_test *test = &misc_test;
1105 IXmlReader *reader;
1106 XmlNodeType type;
1107 IStream *stream;
1108 HRESULT hr;
1109 int i;
1110
1111 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1112 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1113
1114 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1115 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1116 ok(hr == S_OK, "got %08x\n", hr);
1117
1118 i = 0;
1119 type = XmlNodeType_None;
1120 hr = IXmlReader_Read(reader, &type);
1121 while (hr == S_OK)
1122 {
1123 ok(test->types[i] != XmlNodeType_None, "%d: unexpected end of test data\n", i);
1124 if (test->types[i] == XmlNodeType_None) break;
1125 ok(type == test->types[i], "%d: got wrong type %d, expected %d\n", i, type, test->types[i]);
1126 if (type == XmlNodeType_Whitespace)
1127 {
1128 const WCHAR *ptr;
1129 UINT len = 0;
1130
1131 hr = IXmlReader_GetValue(reader, &ptr, &len);
1132 ok(hr == S_OK, "%d: GetValue failed 0x%08x\n", i, hr);
1133 ok(len > 0, "%d: wrong value length %d\n", i, len);
1134 }
1135 hr = IXmlReader_Read(reader, &type);
1136 i++;
1137 }
1138 ok(test->types[i] == XmlNodeType_None, "incomplete sequence, got %d\n", test->types[i]);
1139
1140 IStream_Release(stream);
1141 IXmlReader_Release(reader);
1142 }
1143
1144 static const char test_dtd[] =
1145 "<!DOCTYPE testdtd SYSTEM \"externalid uri\" >"
1146 "<!-- comment -->";
1147
1148 static void test_read_dtd(void)
1149 {
1150 static const WCHAR sysvalW[] = {'e','x','t','e','r','n','a','l','i','d',' ','u','r','i',0};
1151 static const WCHAR dtdnameW[] = {'t','e','s','t','d','t','d',0};
1152 static const WCHAR sysW[] = {'S','Y','S','T','E','M',0};
1153 IXmlReader *reader;
1154 const WCHAR *str;
1155 XmlNodeType type;
1156 IStream *stream;
1157 UINT len, count;
1158 HRESULT hr;
1159
1160 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1161 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1162
1163 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_DtdProcessing, DtdProcessing_Parse);
1164 ok(hr == S_OK, "got 0x%8x\n", hr);
1165
1166 stream = create_stream_on_data(test_dtd, sizeof(test_dtd));
1167 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1168 ok(hr == S_OK, "got %08x\n", hr);
1169
1170 type = XmlNodeType_None;
1171 hr = IXmlReader_Read(reader, &type);
1172 ok(hr == S_OK, "got 0x%8x\n", hr);
1173 ok(type == XmlNodeType_DocumentType, "got type %d\n", type);
1174
1175 count = 0;
1176 hr = IXmlReader_GetAttributeCount(reader, &count);
1177 ok(hr == S_OK, "got %08x\n", hr);
1178 ok(count == 1, "got %d\n", count);
1179
1180 hr = IXmlReader_MoveToFirstAttribute(reader);
1181 ok(hr == S_OK, "got %08x\n", hr);
1182
1183 type = XmlNodeType_None;
1184 hr = IXmlReader_GetNodeType(reader, &type);
1185 ok(hr == S_OK, "got %08x\n", hr);
1186 ok(type == XmlNodeType_Attribute, "got %d\n", type);
1187
1188 len = 0;
1189 str = NULL;
1190 hr = IXmlReader_GetLocalName(reader, &str, &len);
1191 ok(hr == S_OK, "got 0x%08x\n", hr);
1192 ok(len == lstrlenW(sysW), "got %u\n", len);
1193 ok(!lstrcmpW(str, sysW), "got %s\n", wine_dbgstr_w(str));
1194
1195 len = 0;
1196 str = NULL;
1197 hr = IXmlReader_GetValue(reader, &str, &len);
1198 ok(hr == S_OK, "got 0x%08x\n", hr);
1199 ok(len == lstrlenW(sysvalW), "got %u\n", len);
1200 ok(!lstrcmpW(str, sysvalW), "got %s\n", wine_dbgstr_w(str));
1201
1202 hr = IXmlReader_MoveToElement(reader);
1203 ok(hr == S_OK, "got 0x%08x\n", hr);
1204
1205 len = 0;
1206 str = NULL;
1207 hr = IXmlReader_GetLocalName(reader, &str, &len);
1208 ok(hr == S_OK, "got 0x%08x\n", hr);
1209 todo_wine {
1210 ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1211 ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1212 }
1213 len = 0;
1214 str = NULL;
1215 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1216 ok(hr == S_OK, "got 0x%08x\n", hr);
1217 ok(len == lstrlenW(dtdnameW), "got %u\n", len);
1218 ok(!lstrcmpW(str, dtdnameW), "got %s\n", wine_dbgstr_w(str));
1219
1220 type = XmlNodeType_None;
1221 hr = IXmlReader_Read(reader, &type);
1222 ok(hr == S_OK, "got 0x%8x\n", hr);
1223 ok(type == XmlNodeType_Comment, "got type %d\n", type);
1224
1225 IStream_Release(stream);
1226 IXmlReader_Release(reader);
1227 }
1228
1229 static struct test_entry element_tests[] = {
1230 { "<a/>", "a", "", S_OK },
1231 { "<a />", "a", "", S_OK },
1232 { "<a:b/>", "a:b", "", NC_E_UNDECLAREDPREFIX },
1233 { "<:a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1234 { "< a/>", NULL, NULL, NC_E_QNAMECHARACTER },
1235 { "<a>", "a", "", S_OK },
1236 { "<a >", "a", "", S_OK },
1237 { "<a \r \t\n>", "a", "", S_OK },
1238 { "</a>", NULL, NULL, NC_E_QNAMECHARACTER },
1239 { NULL }
1240 };
1241
1242 static void test_read_element(void)
1243 {
1244 struct test_entry *test = element_tests;
1245 static const char stag[] = "<a><b></b></a>";
1246 static const char mismatch[] = "<a></b>";
1247 IXmlReader *reader;
1248 XmlNodeType type;
1249 IStream *stream;
1250 UINT depth;
1251 HRESULT hr;
1252
1253 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1254 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1255
1256 while (test->xml)
1257 {
1258 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1259 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1260 ok(hr == S_OK, "got %08x\n", hr);
1261
1262 type = XmlNodeType_None;
1263 hr = IXmlReader_Read(reader, &type);
1264 if (test->hr_broken)
1265 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1266 else
1267 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1268 if (hr == S_OK)
1269 {
1270 const WCHAR *str;
1271 WCHAR *str_exp;
1272 UINT len;
1273
1274 ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
1275
1276 len = 0;
1277 str = NULL;
1278 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1279 ok(hr == S_OK, "got 0x%08x\n", hr);
1280 ok(len == strlen(test->name), "got %u\n", len);
1281 str_exp = a2w(test->name);
1282 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1283 free_str(str_exp);
1284
1285 /* value */
1286 len = 1;
1287 str = NULL;
1288 hr = IXmlReader_GetValue(reader, &str, &len);
1289 ok(hr == S_OK, "got 0x%08x\n", hr);
1290 ok(len == 0, "got %u\n", len);
1291 ok(*str == 0, "got %s\n", wine_dbgstr_w(str));
1292 }
1293
1294 IStream_Release(stream);
1295 test++;
1296 }
1297
1298 /* test reader depth increment */
1299 stream = create_stream_on_data(stag, sizeof(stag));
1300 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1301 ok(hr == S_OK, "got %08x\n", hr);
1302
1303 depth = 1;
1304 hr = IXmlReader_GetDepth(reader, &depth);
1305 ok(hr == S_OK, "got %08x\n", hr);
1306 ok(depth == 0, "got %d\n", depth);
1307
1308 type = XmlNodeType_None;
1309 hr = IXmlReader_Read(reader, &type);
1310 ok(hr == S_OK, "got %08x\n", hr);
1311 ok(type == XmlNodeType_Element, "got %d\n", type);
1312
1313 depth = 1;
1314 hr = IXmlReader_GetDepth(reader, &depth);
1315 ok(hr == S_OK, "got %08x\n", hr);
1316 ok(depth == 0, "got %d\n", depth);
1317
1318 type = XmlNodeType_None;
1319 hr = IXmlReader_Read(reader, &type);
1320 ok(hr == S_OK, "got %08x\n", hr);
1321 ok(type == XmlNodeType_Element, "got %d\n", type);
1322
1323 depth = 0;
1324 hr = IXmlReader_GetDepth(reader, &depth);
1325 ok(hr == S_OK, "got %08x\n", hr);
1326 ok(depth == 1, "got %d\n", depth);
1327
1328 /* read end tag for inner element */
1329 type = XmlNodeType_None;
1330 hr = IXmlReader_Read(reader, &type);
1331 ok(hr == S_OK, "got %08x\n", hr);
1332 ok(type == XmlNodeType_EndElement, "got %d\n", type);
1333
1334 depth = 0;
1335 hr = IXmlReader_GetDepth(reader, &depth);
1336 ok(hr == S_OK, "got %08x\n", hr);
1337 todo_wine
1338 ok(depth == 2, "got %d\n", depth);
1339
1340 /* read end tag for container element */
1341 type = XmlNodeType_None;
1342 hr = IXmlReader_Read(reader, &type);
1343 ok(hr == S_OK, "got %08x\n", hr);
1344 ok(type == XmlNodeType_EndElement, "got %d\n", type);
1345
1346 depth = 0;
1347 hr = IXmlReader_GetDepth(reader, &depth);
1348 ok(hr == S_OK, "got %08x\n", hr);
1349 ok(depth == 1, "got %d\n", depth);
1350
1351 IStream_Release(stream);
1352
1353 /* start/end tag mismatch */
1354 stream = create_stream_on_data(mismatch, sizeof(mismatch));
1355 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1356 ok(hr == S_OK, "got %08x\n", hr);
1357
1358 type = XmlNodeType_None;
1359 hr = IXmlReader_Read(reader, &type);
1360 ok(hr == S_OK, "got %08x\n", hr);
1361 ok(type == XmlNodeType_Element, "got %d\n", type);
1362
1363 type = XmlNodeType_Element;
1364 hr = IXmlReader_Read(reader, &type);
1365 ok(hr == WC_E_ELEMENTMATCH, "got %08x\n", hr);
1366 todo_wine
1367 ok(type == XmlNodeType_None, "got %d\n", type);
1368
1369 IStream_Release(stream);
1370
1371 IXmlReader_Release(reader);
1372 }
1373
1374 static ISequentialStream teststream = { &teststreamvtbl };
1375
1376 static void test_read_pending(void)
1377 {
1378 IXmlReader *reader;
1379 const WCHAR *value;
1380 XmlNodeType type;
1381 HRESULT hr;
1382 int c;
1383
1384 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1385 ok(hr == S_OK, "S_OK, got 0x%08x\n", hr);
1386
1387 hr = IXmlReader_SetInput(reader, (IUnknown*)&teststream);
1388 ok(hr == S_OK, "got 0x%08x\n", hr);
1389
1390 /* first read call returns incomplete node, second attempt fails with E_PENDING */
1391 stream_readcall = 0;
1392 type = XmlNodeType_Element;
1393 hr = IXmlReader_Read(reader, &type);
1394 ok(hr == S_OK || broken(hr == E_PENDING), "got 0x%08x\n", hr);
1395 /* newer versions are happy when it's enough data to detect node type,
1396 older versions keep reading until it fails to read more */
1397 ok(stream_readcall == 1 || broken(stream_readcall > 1), "got %d\n", stream_readcall);
1398 ok(type == XmlNodeType_Comment || broken(type == XmlNodeType_None), "got %d\n", type);
1399
1400 /* newer versions' GetValue() makes an attempt to read more */
1401 c = stream_readcall;
1402 value = (void*)0xdeadbeef;
1403 hr = IXmlReader_GetValue(reader, &value, NULL);
1404 ok(hr == E_PENDING, "got 0x%08x\n", hr);
1405 ok(value == NULL || broken(value == (void*)0xdeadbeef) /* Win8 sets it to NULL */, "got %p\n", value);
1406 ok(c < stream_readcall || broken(c == stream_readcall), "got %d, expected %d\n", stream_readcall, c+1);
1407
1408 IXmlReader_Release(reader);
1409 }
1410
1411 static void test_readvaluechunk(void)
1412 {
1413 static const char testA[] = "<!-- comment1 -->";
1414 IXmlReader *reader;
1415 XmlNodeType type;
1416 IStream *stream;
1417 const WCHAR *value;
1418 WCHAR b;
1419 HRESULT hr;
1420 UINT c;
1421
1422 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1423 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1424
1425 stream = create_stream_on_data(testA, sizeof(testA));
1426 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1427 ok(hr == S_OK, "got %08x\n", hr);
1428
1429 hr = IXmlReader_Read(reader, &type);
1430 ok(hr == S_OK, "got %08x\n", hr);
1431
1432 c = 0;
1433 b = 0;
1434 hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1435 ok(hr == S_OK, "got %08x\n", hr);
1436 ok(c == 1, "got %u\n", c);
1437 ok(b == ' ', "got %x\n", b);
1438
1439 /* portion read as chunk is skipped from resulting node value */
1440 value = NULL;
1441 hr = IXmlReader_GetValue(reader, &value, NULL);
1442 ok(hr == S_OK, "got %08x\n", hr);
1443 ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1444
1445 /* once value is returned/allocated it's not possible to read by chunk */
1446 c = 0;
1447 b = 0;
1448 hr = IXmlReader_ReadValueChunk(reader, &b, 1, &c);
1449 ok(hr == S_FALSE, "got %08x\n", hr);
1450 ok(c == 0, "got %u\n", c);
1451 ok(b == 0, "got %x\n", b);
1452
1453 value = NULL;
1454 hr = IXmlReader_GetValue(reader, &value, NULL);
1455 ok(hr == S_OK, "got %08x\n", hr);
1456 ok(value[0] == 'c', "got %s\n", wine_dbgstr_w(value));
1457
1458 IXmlReader_Release(reader);
1459 IStream_Release(stream);
1460 }
1461
1462 static struct test_entry cdata_tests[] = {
1463 { "<a><![CDATA[ ]]data ]]></a>", "", " ]]data ", S_OK },
1464 { "<a><![CDATA[<![CDATA[ data ]]]]></a>", "", "<![CDATA[ data ]]", S_OK },
1465 { "<a><![CDATA[\n \r\n \n\n ]]></a>", "", "\n \n \n\n ", S_OK, S_OK, TRUE },
1466 { "<a><![CDATA[\r \r\r\n \n\n ]]></a>", "", "\n \n\n \n\n ", S_OK, S_OK, TRUE },
1467 { "<a><![CDATA[\r\r \n\r \r \n\n ]]></a>", "", "\n\n \n\n \n \n\n ", S_OK },
1468 { NULL }
1469 };
1470
1471 static void test_read_cdata(void)
1472 {
1473 struct test_entry *test = cdata_tests;
1474 IXmlReader *reader;
1475 HRESULT hr;
1476
1477 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1478 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1479
1480 while (test->xml)
1481 {
1482 XmlNodeType type;
1483 IStream *stream;
1484
1485 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1486 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1487 ok(hr == S_OK, "got %08x\n", hr);
1488
1489 type = XmlNodeType_None;
1490 hr = IXmlReader_Read(reader, &type);
1491
1492 /* read one more to get to CDATA */
1493 if (type == XmlNodeType_Element)
1494 {
1495 type = XmlNodeType_None;
1496 hr = IXmlReader_Read(reader, &type);
1497 }
1498
1499 if (test->hr_broken)
1500 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1501 else
1502 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1503 if (hr == S_OK)
1504 {
1505 const WCHAR *str;
1506 WCHAR *str_exp;
1507 UINT len;
1508
1509 ok(type == XmlNodeType_CDATA, "got %d for %s\n", type, test->xml);
1510
1511 str_exp = a2w(test->name);
1512
1513 len = 1;
1514 str = NULL;
1515 hr = IXmlReader_GetLocalName(reader, &str, &len);
1516 ok(hr == S_OK, "got 0x%08x\n", hr);
1517 ok(len == strlen(test->name), "got %u\n", len);
1518 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1519
1520 str = NULL;
1521 hr = IXmlReader_GetLocalName(reader, &str, NULL);
1522 ok(hr == S_OK, "got 0x%08x\n", hr);
1523 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1524
1525 free_str(str_exp);
1526
1527 len = 1;
1528 str = NULL;
1529 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1530 ok(hr == S_OK, "got 0x%08x\n", hr);
1531 ok(len == strlen(test->name), "got %u\n", len);
1532 str_exp = a2w(test->name);
1533 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1534 free_str(str_exp);
1535
1536 /* value */
1537 len = 1;
1538 str = NULL;
1539 hr = IXmlReader_GetValue(reader, &str, &len);
1540 ok(hr == S_OK, "got 0x%08x\n", hr);
1541
1542 str_exp = a2w(test->value);
1543 todo_wine_if (test->todo)
1544 {
1545 ok(len == strlen(test->value), "got %u\n", len);
1546 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1547 }
1548 free_str(str_exp);
1549 }
1550
1551 IStream_Release(stream);
1552 test++;
1553 }
1554
1555 IXmlReader_Release(reader);
1556 }
1557
1558 static struct test_entry text_tests[] = {
1559 { "<a>simple text</a>", "", "simple text", S_OK },
1560 { "<a>text ]]> text</a>", "", "", WC_E_CDSECTEND },
1561 { NULL }
1562 };
1563
1564 static void test_read_text(void)
1565 {
1566 struct test_entry *test = text_tests;
1567 IXmlReader *reader;
1568 HRESULT hr;
1569
1570 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1571 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1572
1573 while (test->xml)
1574 {
1575 XmlNodeType type;
1576 IStream *stream;
1577
1578 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1579 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1580 ok(hr == S_OK, "got %08x\n", hr);
1581
1582 type = XmlNodeType_None;
1583 hr = IXmlReader_Read(reader, &type);
1584
1585 /* read one more to get to CDATA */
1586 if (type == XmlNodeType_Element)
1587 {
1588 type = XmlNodeType_None;
1589 hr = IXmlReader_Read(reader, &type);
1590 }
1591
1592 if (test->hr_broken)
1593 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1594 else
1595 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1596 if (hr == S_OK)
1597 {
1598 const WCHAR *str;
1599 WCHAR *str_exp;
1600 UINT len;
1601
1602 ok(type == XmlNodeType_Text, "got %d for %s\n", type, test->xml);
1603
1604 str_exp = a2w(test->name);
1605
1606 len = 1;
1607 str = NULL;
1608 hr = IXmlReader_GetLocalName(reader, &str, &len);
1609 ok(hr == S_OK, "got 0x%08x\n", hr);
1610 ok(len == strlen(test->name), "got %u\n", len);
1611 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1612
1613 str = NULL;
1614 hr = IXmlReader_GetLocalName(reader, &str, NULL);
1615 ok(hr == S_OK, "got 0x%08x\n", hr);
1616 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1617
1618 free_str(str_exp);
1619
1620 len = 1;
1621 str = NULL;
1622 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1623 ok(hr == S_OK, "got 0x%08x\n", hr);
1624 ok(len == strlen(test->name), "got %u\n", len);
1625 str_exp = a2w(test->name);
1626 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1627 free_str(str_exp);
1628
1629 /* value */
1630 len = 1;
1631 str = NULL;
1632 hr = IXmlReader_GetValue(reader, &str, &len);
1633 ok(hr == S_OK, "got 0x%08x\n", hr);
1634
1635 str_exp = a2w(test->value);
1636 todo_wine_if (test->todo)
1637 {
1638 ok(len == strlen(test->value), "got %u\n", len);
1639 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1640 }
1641 free_str(str_exp);
1642 }
1643
1644 IStream_Release(stream);
1645 test++;
1646 }
1647
1648 IXmlReader_Release(reader);
1649 }
1650
1651 struct test_entry_empty {
1652 const char *xml;
1653 BOOL empty;
1654 };
1655
1656 static struct test_entry_empty empty_element_tests[] = {
1657 { "<a></a>", FALSE },
1658 { "<a/>", TRUE },
1659 { NULL }
1660 };
1661
1662 static void test_isemptyelement(void)
1663 {
1664 struct test_entry_empty *test = empty_element_tests;
1665 IXmlReader *reader;
1666 HRESULT hr;
1667
1668 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1669 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1670
1671 while (test->xml)
1672 {
1673 XmlNodeType type;
1674 IStream *stream;
1675 BOOL ret;
1676
1677 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1678 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1679 ok(hr == S_OK, "got %08x\n", hr);
1680
1681 type = XmlNodeType_None;
1682 hr = IXmlReader_Read(reader, &type);
1683 ok(hr == S_OK, "got 0x%08x\n", hr);
1684 ok(type == XmlNodeType_Element, "got %d\n", type);
1685
1686 ret = IXmlReader_IsEmptyElement(reader);
1687 ok(ret == test->empty, "got %d, expected %d. xml=%s\n", ret, test->empty, test->xml);
1688
1689 IStream_Release(stream);
1690 test++;
1691 }
1692
1693 IXmlReader_Release(reader);
1694 }
1695
1696 static struct test_entry attributes_tests[] = {
1697 { "<a attr1=\"attrvalue\"/>", "attr1", "attrvalue", S_OK },
1698 { "<a attr1=\"a\'\'ttrvalue\"/>", "attr1", "a\'\'ttrvalue", S_OK },
1699 { "<a attr1=\'a\"ttrvalue\'/>", "attr1", "a\"ttrvalue", S_OK },
1700 { "<a attr1=\' \'/>", "attr1", " ", S_OK },
1701 { "<a attr1=\" \"/>", "attr1", " ", S_OK },
1702 { "<a attr1=\"\r\n \r \n \t\n\r\"/>", "attr1", " ", S_OK },
1703 { "<a attr1=\" val \"/>", "attr1", " val ", S_OK },
1704 { "<a attr1=\"\r\n\tval\n\"/>", "attr1", " val ", S_OK },
1705 { "<a attr1=\"val&#32;\"/>", "attr1", "val ", S_OK },
1706 { "<a attr1=\"val&#x20;\"/>", "attr1", "val ", S_OK },
1707 { "<a attr1=\"&lt;&gt;&amp;&apos;&quot;\"/>", "attr1", "<>&\'\"", S_OK },
1708 { "<a attr1=\"&entname;\"/>", NULL, NULL, WC_E_UNDECLAREDENTITY },
1709 { "<a attr1=\"val&#xfffe;\"/>", NULL, NULL, WC_E_XMLCHARACTER },
1710 { "<a attr1=\"val &#a;\"/>", NULL, NULL, WC_E_DIGIT, WC_E_SEMICOLON },
1711 { "<a attr1=\"val &#12a;\"/>", NULL, NULL, WC_E_SEMICOLON },
1712 { "<a attr1=\"val &#x12g;\"/>", NULL, NULL, WC_E_SEMICOLON },
1713 { "<a attr1=\"val &#xg;\"/>", NULL, NULL, WC_E_HEXDIGIT, WC_E_SEMICOLON },
1714 { "<a attr1=attrvalue/>", NULL, NULL, WC_E_QUOTE },
1715 { "<a attr1=\"attr<value\"/>", NULL, NULL, WC_E_LESSTHAN },
1716 { "<a attr1=\"&entname\"/>", NULL, NULL, WC_E_SEMICOLON },
1717 { NULL }
1718 };
1719
1720 static void test_read_attribute(void)
1721 {
1722 struct test_entry *test = attributes_tests;
1723 IXmlReader *reader;
1724 HRESULT hr;
1725
1726 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1727 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1728
1729 while (test->xml)
1730 {
1731 XmlNodeType type;
1732 IStream *stream;
1733
1734 stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
1735 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
1736 ok(hr == S_OK, "got %08x\n", hr);
1737
1738 type = XmlNodeType_None;
1739 hr = IXmlReader_Read(reader, &type);
1740
1741 if (test->hr_broken)
1742 ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
1743 else
1744 ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
1745 if (hr == S_OK)
1746 {
1747 const WCHAR *str;
1748 WCHAR *str_exp;
1749 UINT len;
1750
1751 ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
1752
1753 hr = IXmlReader_MoveToFirstAttribute(reader);
1754 ok(hr == S_OK, "got 0x%08x\n", hr);
1755
1756 len = 1;
1757 str = NULL;
1758 hr = IXmlReader_GetLocalName(reader, &str, &len);
1759 ok(hr == S_OK, "got 0x%08x\n", hr);
1760 ok(len == strlen(test->name), "got %u\n", len);
1761 str_exp = a2w(test->name);
1762 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1763 free_str(str_exp);
1764
1765 len = 1;
1766 str = NULL;
1767 hr = IXmlReader_GetQualifiedName(reader, &str, &len);
1768 ok(hr == S_OK, "got 0x%08x\n", hr);
1769 todo_wine {
1770 ok(len == strlen(test->name), "got %u\n", len);
1771 str_exp = a2w(test->name);
1772 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1773 free_str(str_exp);
1774 }
1775 /* value */
1776 len = 1;
1777 str = NULL;
1778 hr = IXmlReader_GetValue(reader, &str, &len);
1779 ok(hr == S_OK, "got 0x%08x\n", hr);
1780 ok(len == strlen(test->value), "got %u\n", len);
1781 str_exp = a2w(test->value);
1782 ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
1783 free_str(str_exp);
1784 }
1785
1786 IStream_Release(stream);
1787 test++;
1788 }
1789
1790 IXmlReader_Release(reader);
1791 }
1792
1793 static void test_reader_properties(void)
1794 {
1795 IXmlReader *reader;
1796 HRESULT hr;
1797
1798 hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
1799 ok(hr == S_OK, "S_OK, got %08x\n", hr);
1800
1801 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_MultiLanguage, 0);
1802 ok(hr == S_OK, "SetProperty failed: %08x\n", hr);
1803
1804 hr = IXmlReader_SetProperty(reader, XmlReaderProperty_MaxElementDepth, 0);
1805 ok(hr == S_OK, "SetProperty failed: %08x\n", hr);
1806
1807 IXmlReader_Release(reader);
1808 }
1809
1810 START_TEST(reader)
1811 {
1812 test_reader_create();
1813 test_readerinput();
1814 test_reader_state();
1815 test_read_attribute();
1816 test_read_cdata();
1817 test_read_comment();
1818 test_read_pi();
1819 test_read_dtd();
1820 test_read_element();
1821 test_isemptyelement();
1822 test_read_text();
1823 test_read_full();
1824 test_read_pending();
1825 test_readvaluechunk();
1826 test_read_xmldeclaration();
1827 test_reader_properties();
1828 }