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