xmllite/tests: Fix node type names array, indices are sparse.
[wine.git] / dlls / xmllite / tests / reader.c
blob9bf18ac7f8d0f8383f9b181fca37148c14730bf4
1 /*
2 * XMLLite IXmlReader tests
4 * Copyright 2010 (C) Nikolay Sivov
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.
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.
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
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "initguid.h"
29 #include "ole2.h"
30 #include "xmllite.h"
31 #include "wine/test.h"
33 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
35 HRESULT WINAPI (*pCreateXmlReader)(REFIID riid, void **ppvObject, IMalloc *pMalloc);
36 HRESULT WINAPI (*pCreateXmlReaderInputWithEncodingName)(IUnknown *stream,
37 IMalloc *pMalloc,
38 LPCWSTR encoding,
39 BOOL hint,
40 LPCWSTR base_uri,
41 IXmlReaderInput **ppInput);
42 static const char *debugstr_guid(REFIID riid)
44 static char buf[50];
46 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
47 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
48 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
49 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
51 return buf;
54 static const char xmldecl_full[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
56 static IStream *create_stream_on_data(const char *data, int size)
58 IStream *stream = NULL;
59 HGLOBAL hglobal;
60 void *ptr;
61 HRESULT hr;
63 hglobal = GlobalAlloc(GHND, size);
64 ptr = GlobalLock(hglobal);
66 memcpy(ptr, data, size);
68 hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
69 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
70 ok(stream != NULL, "Expected non-NULL stream\n");
72 GlobalUnlock(hglobal);
74 return stream;
77 static void ok_pos_(IXmlReader *reader, int line, int pos, int line_broken,
78 int pos_broken, int todo, int _line_)
80 UINT l, p;
81 HRESULT hr;
82 int broken_state;
84 hr = IXmlReader_GetLineNumber(reader, &l);
85 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
86 hr = IXmlReader_GetLinePosition(reader, &p);
87 ok_(__FILE__, _line_)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
89 if (line_broken == -1 && pos_broken == -1)
90 broken_state = 0;
91 else
92 broken_state = broken((line_broken == -1 ? line : line_broken) == l &&
93 (pos_broken == -1 ? pos : pos_broken) == p);
95 if (todo)
96 todo_wine
97 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
98 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
99 else
101 ok_(__FILE__, _line_)((l == line && pos == p) || broken_state,
102 "Expected (%d,%d), got (%d,%d)\n", line, pos, l, p);
105 #define ok_pos(reader, l, p, l_brk, p_brk, todo) ok_pos_(reader, l, p, l_brk, p_brk, todo, __LINE__)
107 typedef struct input_iids_t {
108 IID iids[10];
109 int count;
110 } input_iids_t;
112 static const IID *setinput_full[] = {
113 &IID_IXmlReaderInput,
114 &IID_IStream,
115 &IID_ISequentialStream,
116 NULL
119 /* this applies to early xmllite versions */
120 static const IID *setinput_full_old[] = {
121 &IID_IXmlReaderInput,
122 &IID_ISequentialStream,
123 &IID_IStream,
124 NULL
127 /* after ::SetInput(IXmlReaderInput*) */
128 static const IID *setinput_readerinput[] = {
129 &IID_IStream,
130 &IID_ISequentialStream,
131 NULL
134 static const IID *empty_seq[] = {
135 NULL
138 static input_iids_t input_iids;
140 static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line)
142 int i = 0, size = 0;
144 while (expected[i++]) size++;
146 if (todo) {
147 todo_wine
148 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
150 else
151 ok_(__FILE__, line)(iids->count == size, "Sequence size mismatch (%d), got (%d)\n", size, iids->count);
153 if (iids->count != size) return;
155 for (i = 0; i < size; i++) {
156 ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
157 (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE),
158 "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i]));
161 #define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__)
163 static const char *state_to_str(XmlReadState state)
165 static const char* state_names[] = {
166 "XmlReadState_Initial",
167 "XmlReadState_Interactive",
168 "XmlReadState_Error",
169 "XmlReadState_EndOfFile",
170 "XmlReadState_Closed"
173 static const char unknown[] = "unknown";
175 switch (state)
177 case XmlReadState_Initial:
178 case XmlReadState_Interactive:
179 case XmlReadState_Error:
180 case XmlReadState_EndOfFile:
181 case XmlReadState_Closed:
182 return state_names[state];
183 default:
184 return unknown;
188 static const char *type_to_str(XmlNodeType type)
190 static const char* type_names[] = {
191 "XmlNodeType_None",
192 "XmlNodeType_Element",
193 "XmlNodeType_Attribute",
194 "XmlNodeType_Text",
195 "XmlNodeType_CDATA",
196 "", "",
197 "XmlNodeType_ProcessingInstruction",
198 "XmlNodeType_Comment",
200 "XmlNodeType_DocumentType",
201 "", "",
202 "XmlNodeType_Whitespace",
204 "XmlNodeType_EndElement",
206 "XmlNodeType_XmlDeclaration"
209 static const char unknown[] = "unknown";
211 switch (type)
213 case XmlNodeType_None:
214 case XmlNodeType_Element:
215 case XmlNodeType_Attribute:
216 case XmlNodeType_Text:
217 case XmlNodeType_CDATA:
218 case XmlNodeType_ProcessingInstruction:
219 case XmlNodeType_Comment:
220 case XmlNodeType_DocumentType:
221 case XmlNodeType_Whitespace:
222 case XmlNodeType_EndElement:
223 case XmlNodeType_XmlDeclaration:
224 return type_names[type];
225 default:
226 return unknown;
230 static void test_read_state_(IXmlReader *reader, XmlReadState expected,
231 XmlReadState exp_broken, int todo, int line)
233 XmlReadState state;
234 HRESULT hr;
235 int broken_state;
237 state = -1; /* invalid value */
238 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, (LONG_PTR*)&state);
239 ok_(__FILE__, line)(hr == S_OK, "Expected S_OK, got %08x\n", hr);
241 if (exp_broken == -1)
242 broken_state = 0;
243 else
244 broken_state = broken(exp_broken == state);
246 if (todo)
248 todo_wine
249 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
250 state_to_str(expected), state_to_str(state));
252 else
253 ok_(__FILE__, line)(state == expected || broken_state, "Expected (%s), got (%s)\n",
254 state_to_str(expected), state_to_str(state));
257 #define test_read_state(reader, exp, brk, todo) test_read_state_(reader, exp, brk, todo, __LINE__)
259 typedef struct _testinput
261 const IUnknownVtbl *lpVtbl;
262 LONG ref;
263 } testinput;
265 static inline testinput *impl_from_IUnknown(IUnknown *iface)
267 return (testinput *)((char*)iface - FIELD_OFFSET(testinput, lpVtbl));
270 static HRESULT WINAPI testinput_QueryInterface(IUnknown *iface, REFIID riid, void** ppvObj)
272 if (IsEqualGUID( riid, &IID_IUnknown ))
274 *ppvObj = iface;
275 IUnknown_AddRef(iface);
276 return S_OK;
279 input_iids.iids[input_iids.count++] = *riid;
281 *ppvObj = NULL;
283 return E_NOINTERFACE;
286 static ULONG WINAPI testinput_AddRef(IUnknown *iface)
288 testinput *This = impl_from_IUnknown(iface);
289 return InterlockedIncrement(&This->ref);
292 static ULONG WINAPI testinput_Release(IUnknown *iface)
294 testinput *This = impl_from_IUnknown(iface);
295 LONG ref;
297 ref = InterlockedDecrement(&This->ref);
298 if (ref == 0)
300 HeapFree(GetProcessHeap(), 0, This);
303 return ref;
306 static const struct IUnknownVtbl testinput_vtbl =
308 testinput_QueryInterface,
309 testinput_AddRef,
310 testinput_Release
313 static HRESULT testinput_createinstance(void **ppObj)
315 testinput *input;
317 input = HeapAlloc(GetProcessHeap(), 0, sizeof (*input));
318 if(!input) return E_OUTOFMEMORY;
320 input->lpVtbl = &testinput_vtbl;
321 input->ref = 1;
323 *ppObj = &input->lpVtbl;
325 return S_OK;
328 static BOOL init_pointers(void)
330 /* don't free module here, it's to be unloaded on exit */
331 HMODULE mod = LoadLibraryA("xmllite.dll");
333 if (!mod)
335 win_skip("xmllite library not available\n");
336 return FALSE;
339 #define MAKEFUNC(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return FALSE;
340 MAKEFUNC(CreateXmlReader);
341 MAKEFUNC(CreateXmlReaderInputWithEncodingName);
342 #undef MAKEFUNC
344 return TRUE;
347 static void test_reader_create(void)
349 HRESULT hr;
350 IXmlReader *reader;
351 IUnknown *input;
353 /* crashes native */
354 if (0)
356 hr = pCreateXmlReader(&IID_IXmlReader, NULL, NULL);
357 hr = pCreateXmlReader(NULL, (LPVOID*)&reader, NULL);
360 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
361 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
363 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
365 /* Null input pointer, releases previous input */
366 hr = IXmlReader_SetInput(reader, NULL);
367 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
369 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
371 /* test input interface selection sequence */
372 hr = testinput_createinstance((void**)&input);
373 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
375 input_iids.count = 0;
376 hr = IXmlReader_SetInput(reader, input);
377 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
378 ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE);
380 IUnknown_Release(input);
382 IXmlReader_Release(reader);
385 static void test_readerinput(void)
387 IXmlReaderInput *reader_input;
388 IXmlReader *reader, *reader2;
389 IUnknown *obj, *input;
390 IStream *stream;
391 HRESULT hr;
392 LONG ref;
394 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, NULL);
395 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
396 hr = pCreateXmlReaderInputWithEncodingName(NULL, NULL, NULL, FALSE, NULL, &reader_input);
397 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
399 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
400 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
402 ref = IStream_AddRef(stream);
403 ok(ref == 2, "Expected 2, got %d\n", ref);
404 IStream_Release(stream);
405 hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
406 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
408 /* IXmlReaderInput grabs a stream reference */
409 ref = IStream_AddRef(stream);
410 ok(ref == 3, "Expected 3, got %d\n", ref);
411 IStream_Release(stream);
413 /* try ::SetInput() with valid IXmlReaderInput */
414 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
415 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
417 ref = IUnknown_AddRef(reader_input);
418 ok(ref == 2, "Expected 2, got %d\n", ref);
419 IUnknown_Release(reader_input);
421 hr = IXmlReader_SetInput(reader, reader_input);
422 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
424 test_read_state(reader, XmlReadState_Initial, -1, FALSE);
426 /* IXmlReader grabs a IXmlReaderInput reference */
427 ref = IUnknown_AddRef(reader_input);
428 ok(ref == 3, "Expected 3, got %d\n", ref);
429 IUnknown_Release(reader_input);
431 ref = IStream_AddRef(stream);
432 ok(ref == 4, "Expected 4, got %d\n", ref);
433 IStream_Release(stream);
435 /* reset input and check state */
436 hr = IXmlReader_SetInput(reader, NULL);
437 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
439 test_read_state(reader, XmlReadState_Initial, XmlReadState_Closed, FALSE);
441 IXmlReader_Release(reader);
443 ref = IStream_AddRef(stream);
444 ok(ref == 3, "Expected 3, got %d\n", ref);
445 IStream_Release(stream);
447 ref = IUnknown_AddRef(reader_input);
448 ok(ref == 2, "Expected 2, got %d\n", ref);
449 IUnknown_Release(reader_input);
451 /* IID_IXmlReaderInput */
452 /* it returns a kind of private undocumented vtable incompatible with IUnknown,
453 so it's not a COM interface actually.
454 Such query will be used only to check if input is really IXmlReaderInput */
455 obj = (IUnknown*)0xdeadbeef;
456 hr = IUnknown_QueryInterface(reader_input, &IID_IXmlReaderInput, (void**)&obj);
457 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
458 ref = IUnknown_AddRef(reader_input);
459 ok(ref == 3, "Expected 3, got %d\n", ref);
460 IUnknown_Release(reader_input);
462 IUnknown_Release(reader_input);
463 IUnknown_Release(reader_input);
464 IStream_Release(stream);
466 /* test input interface selection sequence */
467 hr = testinput_createinstance((void**)&input);
468 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
470 input_iids.count = 0;
471 ref = IUnknown_AddRef(input);
472 ok(ref == 2, "Expected 2, got %d\n", ref);
473 IUnknown_Release(input);
474 hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input);
475 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
476 ok_iids(&input_iids, empty_seq, NULL, FALSE);
477 /* IXmlReaderInput stores stream interface as IUnknown */
478 ref = IUnknown_AddRef(input);
479 ok(ref == 3, "Expected 3, got %d\n", ref);
480 IUnknown_Release(input);
482 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
483 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
485 input_iids.count = 0;
486 ref = IUnknown_AddRef(reader_input);
487 ok(ref == 2, "Expected 2, got %d\n", ref);
488 IUnknown_Release(reader_input);
489 ref = IUnknown_AddRef(input);
490 ok(ref == 3, "Expected 3, got %d\n", ref);
491 IUnknown_Release(input);
492 hr = IXmlReader_SetInput(reader, reader_input);
493 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
494 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
496 test_read_state(reader, XmlReadState_Closed, -1, FALSE);
498 ref = IUnknown_AddRef(input);
499 ok(ref == 3, "Expected 3, got %d\n", ref);
500 IUnknown_Release(input);
502 ref = IUnknown_AddRef(reader_input);
503 ok(ref == 3 || broken(ref == 2) /* versions 1.0.x and 1.1.x - XP, Vista */,
504 "Expected 3, got %d\n", ref);
505 IUnknown_Release(reader_input);
506 /* repeat another time, no check or caching here */
507 input_iids.count = 0;
508 hr = IXmlReader_SetInput(reader, reader_input);
509 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
510 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
512 /* another reader */
513 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL);
514 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
516 /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at
517 ::SetInput() level, each time it's called */
518 input_iids.count = 0;
519 hr = IXmlReader_SetInput(reader2, reader_input);
520 ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr);
521 ok_iids(&input_iids, setinput_readerinput, NULL, FALSE);
523 IXmlReader_Release(reader2);
524 IXmlReader_Release(reader);
526 IUnknown_Release(reader_input);
527 IUnknown_Release(input);
530 static void test_reader_state(void)
532 IXmlReader *reader;
533 HRESULT hr;
535 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
536 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
538 /* invalid arguments */
539 hr = IXmlReader_GetProperty(reader, XmlReaderProperty_ReadState, NULL);
540 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
542 IXmlReader_Release(reader);
545 static void test_read_xmldeclaration(void)
547 IXmlReader *reader;
548 IStream *stream;
549 HRESULT hr;
550 XmlNodeType type;
551 UINT count = 0;
553 hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL);
554 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
556 /* position methods with Null args */
557 hr = IXmlReader_GetLineNumber(reader, NULL);
558 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
560 hr = IXmlReader_GetLinePosition(reader, NULL);
561 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
563 stream = create_stream_on_data(xmldecl_full, sizeof(xmldecl_full));
565 hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
566 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
568 ok_pos(reader, 0, 0, -1, -1, FALSE);
570 type = -1;
571 hr = IXmlReader_Read(reader, &type);
572 todo_wine {
573 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
574 ok(type == XmlNodeType_XmlDeclaration,
575 "Expected XmlNodeType_XmlDeclaration, got %s\n", type_to_str(type));
577 /* new version 1.2.x and 1.3.x properly update postition for <?xml ?> */
578 ok_pos(reader, 1, 3, -1, 55, TRUE);
580 /* check attributes */
581 hr = IXmlReader_MoveToNextAttribute(reader);
582 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
583 ok_pos(reader, 1, 7, -1, 55, TRUE);
585 hr = IXmlReader_MoveToFirstAttribute(reader);
586 todo_wine ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
587 ok_pos(reader, 1, 7, -1, 55, TRUE);
589 hr = IXmlReader_GetAttributeCount(reader, &count);
590 todo_wine {
591 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
592 ok(count == 3, "Expected 3, got %d\n", count);
594 hr = IXmlReader_GetDepth(reader, &count);
595 todo_wine {
596 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
597 ok(count == 1, "Expected 1, got %d\n", count);
600 IStream_Release(stream);
601 IXmlReader_Release(reader);
604 START_TEST(reader)
606 HRESULT r;
608 r = CoInitialize( NULL );
609 ok( r == S_OK, "failed to init com\n");
611 if (!init_pointers())
613 CoUninitialize();
614 return;
617 test_reader_create();
618 test_readerinput();
619 test_reader_state();
620 test_read_xmldeclaration();
622 CoUninitialize();