3eb67314e7531384d0a108c18a5800bb4bdf59fb
[reactos.git] / rostests / winetests / xmllite / writer.c
1 /*
2 * XMLLite IXmlWriter tests
3 *
4 * Copyright 2011 (C) Alistair Leslie-Hughes
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 CONST_VTABLE
26 #define COBJMACROS
27
28 #include <stdarg.h>
29 //#include <stdio.h>
30
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnls.h>
34 #include <objbase.h>
35 #include <ole2.h>
36 #include <xmllite.h>
37 #include <wine/test.h>
38
39 #include <initguid.h>
40 DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
41
42 static void check_output(IStream *stream, const char *expected, int line)
43 {
44 HGLOBAL hglobal;
45 int len = strlen(expected), size;
46 char *ptr;
47 HRESULT hr;
48
49 hr = GetHGlobalFromStream(stream, &hglobal);
50 ok_(__FILE__, line)(hr == S_OK, "got 0x%08x\n", hr);
51
52 size = GlobalSize(hglobal);
53 ptr = GlobalLock(hglobal);
54 if (size != len)
55 {
56 ok_(__FILE__, line)(0, "data size mismatch, expected %u, got %u\n", len, size);
57 ok_(__FILE__, line)(0, "got %s, expected %s\n", ptr, expected);
58 }
59 else
60 ok_(__FILE__, line)(!strncmp(ptr, expected, len), "got %s, expected %s\n", ptr, expected);
61 GlobalUnlock(hglobal);
62 }
63 #define CHECK_OUTPUT(stream, expected) check_output(stream, expected, __LINE__)
64
65 /* used to test all Write* methods for consistent error state */
66 static void check_writer_state(IXmlWriter *writer, HRESULT exp_hr)
67 {
68 static const WCHAR aW[] = {'a',0};
69 HRESULT hr;
70
71 /* FIXME: add WriteAttributes */
72
73 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
74 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
75
76 hr = IXmlWriter_WriteCData(writer, aW);
77 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
78
79 hr = IXmlWriter_WriteCharEntity(writer, aW[0]);
80 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
81
82 hr = IXmlWriter_WriteChars(writer, aW, 1);
83 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
84
85 hr = IXmlWriter_WriteComment(writer, aW);
86 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
87
88 /* FIXME: add WriteDocType */
89
90 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
91 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
92
93 hr = IXmlWriter_WriteEndDocument(writer);
94 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
95
96 hr = IXmlWriter_WriteEndElement(writer);
97 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
98
99 hr = IXmlWriter_WriteEntityRef(writer, aW);
100 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
101
102 hr = IXmlWriter_WriteFullEndElement(writer);
103 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
104
105 hr = IXmlWriter_WriteName(writer, aW);
106 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
107
108 hr = IXmlWriter_WriteNmToken(writer, aW);
109 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
110
111 /* FIXME: add WriteNode */
112 /* FIXME: add WriteNodeShallow */
113
114 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
115 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
116
117 hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL);
118 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
119
120 hr = IXmlWriter_WriteRaw(writer, aW);
121 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
122
123 hr = IXmlWriter_WriteRawChars(writer, aW, 1);
124 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
125
126 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
127 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
128
129 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
130 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
131
132 hr = IXmlWriter_WriteString(writer, aW);
133 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
134
135 /* FIXME: add WriteSurrogateCharEntity */
136 /* FIXME: add WriteWhitespace */
137 }
138
139 static IStream *writer_set_output(IXmlWriter *writer)
140 {
141 IStream *stream;
142 HRESULT hr;
143
144 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
145 ok(hr == S_OK, "got 0x%08x\n", hr);
146
147 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
148 ok(hr == S_OK, "got 0x%08x\n", hr);
149
150 return stream;
151 }
152
153 static HRESULT WINAPI testoutput_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
154 {
155 if (IsEqualGUID(riid, &IID_IUnknown)) {
156 *obj = iface;
157 return S_OK;
158 }
159 else {
160 ok(0, "unknown riid=%s\n", wine_dbgstr_guid(riid));
161 return E_NOINTERFACE;
162 }
163 }
164
165 static ULONG WINAPI testoutput_AddRef(IUnknown *iface)
166 {
167 return 2;
168 }
169
170 static ULONG WINAPI testoutput_Release(IUnknown *iface)
171 {
172 return 1;
173 }
174
175 static const IUnknownVtbl testoutputvtbl = {
176 testoutput_QueryInterface,
177 testoutput_AddRef,
178 testoutput_Release
179 };
180
181 static IUnknown testoutput = { &testoutputvtbl };
182
183 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
184 {
185 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
186 {
187 *obj = iface;
188 return S_OK;
189 }
190
191 *obj = NULL;
192 return E_NOINTERFACE;
193 }
194
195 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
196 {
197 return 2;
198 }
199
200 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
201 {
202 return 1;
203 }
204
205 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
206 {
207 ok(0, "unexpected call\n");
208 return E_NOTIMPL;
209 }
210
211 static ULONG g_write_len;
212 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
213 {
214 g_write_len = cb;
215 *written = cb;
216 return S_OK;
217 }
218
219 static const ISequentialStreamVtbl teststreamvtbl =
220 {
221 teststream_QueryInterface,
222 teststream_AddRef,
223 teststream_Release,
224 teststream_Read,
225 teststream_Write
226 };
227
228 static ISequentialStream teststream = { &teststreamvtbl };
229
230 static void test_writer_create(void)
231 {
232 HRESULT hr;
233 IXmlWriter *writer;
234 LONG_PTR value;
235
236 /* crashes native */
237 if (0)
238 {
239 CreateXmlWriter(&IID_IXmlWriter, NULL, NULL);
240 CreateXmlWriter(NULL, (void**)&writer, NULL);
241 }
242
243 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
244 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
245
246 /* check default properties values */
247 value = 0;
248 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ByteOrderMark, &value);
249 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
250 ok(value == TRUE, "got %ld\n", value);
251
252 value = TRUE;
253 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_Indent, &value);
254 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
255 ok(value == FALSE, "got %ld\n", value);
256
257 value = TRUE;
258 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, &value);
259 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
260 ok(value == FALSE, "got %ld\n", value);
261
262 value = XmlConformanceLevel_Auto;
263 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ConformanceLevel, &value);
264 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
265 ok(value == XmlConformanceLevel_Document, "got %ld\n", value);
266
267 IXmlWriter_Release(writer);
268 }
269
270 static void test_writeroutput(void)
271 {
272 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
273 IXmlWriterOutput *output;
274 IUnknown *unk;
275 HRESULT hr;
276
277 output = NULL;
278 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, NULL, &output);
279 ok(hr == S_OK, "got %08x\n", hr);
280 IUnknown_Release(output);
281
282 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, utf16W, &output);
283 ok(hr == S_OK, "got %08x\n", hr);
284 unk = NULL;
285 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
286 ok(hr == S_OK, "got %08x\n", hr);
287 ok(unk != NULL, "got %p\n", unk);
288 /* releasing 'unk' crashes on native */
289 IUnknown_Release(output);
290
291 output = NULL;
292 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, ~0u, &output);
293 ok(hr == S_OK, "got %08x\n", hr);
294 IUnknown_Release(output);
295
296 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, CP_UTF8, &output);
297 ok(hr == S_OK, "got %08x\n", hr);
298 unk = NULL;
299 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
300 ok(hr == S_OK, "got %08x\n", hr);
301 ok(unk != NULL, "got %p\n", unk);
302 /* releasing 'unk' crashes on native */
303 IUnknown_Release(output);
304 }
305
306 static void test_writestartdocument(void)
307 {
308 static const char fullprolog[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
309 static const char prologversion[] = "<?xml version=\"1.0\"?>";
310 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
311 static const WCHAR xmlW[] = {'x','m','l',0};
312 IXmlWriter *writer;
313 IStream *stream;
314 HRESULT hr;
315
316 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
317 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
318
319 /* output not set */
320 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
321 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
322
323 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
324 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
325
326 hr = IXmlWriter_Flush(writer);
327 ok(hr == S_OK, "got 0x%08x\n", hr);
328
329 stream = writer_set_output(writer);
330
331 /* nothing written yet */
332 hr = IXmlWriter_Flush(writer);
333 ok(hr == S_OK, "got 0x%08x\n", hr);
334
335 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
336 ok(hr == S_OK, "got 0x%08x\n", hr);
337
338 hr = IXmlWriter_Flush(writer);
339 ok(hr == S_OK, "got 0x%08x\n", hr);
340
341 CHECK_OUTPUT(stream, fullprolog);
342
343 /* one more time */
344 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
345 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
346 IStream_Release(stream);
347
348 /* now add PI manually, and try to start a document */
349 stream = writer_set_output(writer);
350
351 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
352 ok(hr == S_OK, "got 0x%08x\n", hr);
353
354 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
355 ok(hr == S_OK, "got 0x%08x\n", hr);
356
357 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
358 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
359
360 /* another attempt to add 'xml' PI */
361 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
362 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
363
364 hr = IXmlWriter_Flush(writer);
365 ok(hr == S_OK, "got 0x%08x\n", hr);
366
367 CHECK_OUTPUT(stream, prologversion);
368
369 IStream_Release(stream);
370 IXmlWriter_Release(writer);
371 }
372
373 static void test_flush(void)
374 {
375 IXmlWriter *writer;
376 HRESULT hr;
377
378 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
379 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
380
381 hr = IXmlWriter_SetOutput(writer, (IUnknown*)&teststream);
382 ok(hr == S_OK, "got 0x%08x\n", hr);
383
384 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
385 ok(hr == S_OK, "got 0x%08x\n", hr);
386
387 g_write_len = 0;
388 hr = IXmlWriter_Flush(writer);
389 ok(hr == S_OK, "got 0x%08x\n", hr);
390 ok(g_write_len > 0, "got %d\n", g_write_len);
391
392 g_write_len = 1;
393 hr = IXmlWriter_Flush(writer);
394 ok(hr == S_OK, "got 0x%08x\n", hr);
395 ok(g_write_len == 0, "got %d\n", g_write_len);
396
397 /* Release() flushes too */
398 g_write_len = 1;
399 IXmlWriter_Release(writer);
400 ok(g_write_len == 0, "got %d\n", g_write_len);
401 }
402
403 static void test_omitxmldeclaration(void)
404 {
405 static const char prologversion[] = "<?xml version=\"1.0\"?>";
406 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
407 static const WCHAR xmlW[] = {'x','m','l',0};
408 IXmlWriter *writer;
409 HGLOBAL hglobal;
410 IStream *stream;
411 HRESULT hr;
412 char *ptr;
413
414 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
415 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
416
417 stream = writer_set_output(writer);
418
419 hr = IXmlWriter_SetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, TRUE);
420 ok(hr == S_OK, "got 0x%08x\n", hr);
421
422 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
423 ok(hr == S_OK, "got 0x%08x\n", hr);
424
425 hr = IXmlWriter_Flush(writer);
426 ok(hr == S_OK, "got 0x%08x\n", hr);
427
428 hr = GetHGlobalFromStream(stream, &hglobal);
429 ok(hr == S_OK, "got 0x%08x\n", hr);
430
431 ptr = GlobalLock(hglobal);
432 ok(!ptr, "got %p\n", ptr);
433 GlobalUnlock(hglobal);
434
435 /* one more time */
436 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
437 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
438
439 IStream_Release(stream);
440
441 /* now add PI manually, and try to start a document */
442 stream = writer_set_output(writer);
443
444 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
445 ok(hr == S_OK, "got 0x%08x\n", hr);
446
447 hr = IXmlWriter_Flush(writer);
448 ok(hr == S_OK, "got 0x%08x\n", hr);
449
450 CHECK_OUTPUT(stream, prologversion);
451
452 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
453 ok(hr == S_OK, "got 0x%08x\n", hr);
454
455 hr = IXmlWriter_Flush(writer);
456 ok(hr == S_OK, "got 0x%08x\n", hr);
457
458 CHECK_OUTPUT(stream, prologversion);
459
460 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
461 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
462
463 hr = IXmlWriter_Flush(writer);
464 ok(hr == S_OK, "got 0x%08x\n", hr);
465
466 CHECK_OUTPUT(stream, prologversion);
467
468 /* another attempt to add 'xml' PI */
469 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
470 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
471
472 hr = IXmlWriter_Flush(writer);
473 ok(hr == S_OK, "got 0x%08x\n", hr);
474
475 IStream_Release(stream);
476 IXmlWriter_Release(writer);
477 }
478
479 static void test_bom(void)
480 {
481 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
482 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
483 static const WCHAR xmlW[] = {'x','m','l',0};
484 static const WCHAR aW[] = {'a',0};
485 IXmlWriterOutput *output;
486 unsigned char *ptr;
487 IXmlWriter *writer;
488 IStream *stream;
489 HGLOBAL hglobal;
490 HRESULT hr;
491
492 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
493 ok(hr == S_OK, "got 0x%08x\n", hr);
494
495 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
496 ok(hr == S_OK, "got %08x\n", hr);
497
498 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
499 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
500
501 hr = IXmlWriter_SetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, TRUE);
502 ok(hr == S_OK, "got 0x%08x\n", hr);
503
504 hr = IXmlWriter_SetOutput(writer, output);
505 ok(hr == S_OK, "got 0x%08x\n", hr);
506
507 /* BOM is on by default */
508 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
509 ok(hr == S_OK, "got 0x%08x\n", hr);
510
511 hr = IXmlWriter_Flush(writer);
512 ok(hr == S_OK, "got 0x%08x\n", hr);
513
514 hr = GetHGlobalFromStream(stream, &hglobal);
515 ok(hr == S_OK, "got 0x%08x\n", hr);
516
517 ptr = GlobalLock(hglobal);
518 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
519 GlobalUnlock(hglobal);
520
521 IStream_Release(stream);
522 IUnknown_Release(output);
523
524 /* start with PI */
525 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
526 ok(hr == S_OK, "got 0x%08x\n", hr);
527
528 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
529 ok(hr == S_OK, "got %08x\n", hr);
530
531 hr = IXmlWriter_SetOutput(writer, output);
532 ok(hr == S_OK, "got 0x%08x\n", hr);
533
534 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
535 ok(hr == S_OK, "got 0x%08x\n", hr);
536
537 hr = IXmlWriter_Flush(writer);
538 ok(hr == S_OK, "got 0x%08x\n", hr);
539
540 hr = GetHGlobalFromStream(stream, &hglobal);
541 ok(hr == S_OK, "got 0x%08x\n", hr);
542
543 ptr = GlobalLock(hglobal);
544 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
545 GlobalUnlock(hglobal);
546
547 IUnknown_Release(output);
548 IStream_Release(stream);
549
550 /* start with element */
551 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
552 ok(hr == S_OK, "got 0x%08x\n", hr);
553
554 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
555 ok(hr == S_OK, "got %08x\n", hr);
556
557 hr = IXmlWriter_SetOutput(writer, output);
558 ok(hr == S_OK, "got 0x%08x\n", hr);
559
560 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
561 ok(hr == S_OK, "got 0x%08x\n", hr);
562
563 hr = IXmlWriter_Flush(writer);
564 ok(hr == S_OK, "got 0x%08x\n", hr);
565
566 hr = GetHGlobalFromStream(stream, &hglobal);
567 ok(hr == S_OK, "got 0x%08x\n", hr);
568
569 ptr = GlobalLock(hglobal);
570 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
571 GlobalUnlock(hglobal);
572
573 IUnknown_Release(output);
574 IStream_Release(stream);
575
576 /* WriteElementString */
577 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
578 ok(hr == S_OK, "got 0x%08x\n", hr);
579
580 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
581 ok(hr == S_OK, "got %08x\n", hr);
582
583 hr = IXmlWriter_SetOutput(writer, output);
584 ok(hr == S_OK, "got 0x%08x\n", hr);
585
586 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL);
587 ok(hr == S_OK, "got 0x%08x\n", hr);
588
589 hr = IXmlWriter_Flush(writer);
590 ok(hr == S_OK, "got 0x%08x\n", hr);
591
592 hr = GetHGlobalFromStream(stream, &hglobal);
593 ok(hr == S_OK, "got 0x%08x\n", hr);
594
595 ptr = GlobalLock(hglobal);
596 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
597 GlobalUnlock(hglobal);
598
599 IUnknown_Release(output);
600 IStream_Release(stream);
601
602 IXmlWriter_Release(writer);
603 }
604
605 static void test_writestartelement(void)
606 {
607 static const WCHAR valueW[] = {'v','a','l','u','e',0};
608 static const char *str = "<a><b>value</b>";
609 static const WCHAR aW[] = {'a',0};
610 static const WCHAR bW[] = {'b',0};
611 IXmlWriter *writer;
612 IStream *stream;
613 HRESULT hr;
614
615 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
616 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
617
618 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
619 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
620
621 stream = writer_set_output(writer);
622
623 hr = IXmlWriter_WriteStartElement(writer, aW, NULL, NULL);
624 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
625
626 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, NULL);
627 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
628
629 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, aW);
630 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
631
632 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
633 ok(hr == S_OK, "got 0x%08x\n", hr);
634
635 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
636 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
637
638 hr = IXmlWriter_Flush(writer);
639 ok(hr == S_OK, "got 0x%08x\n", hr);
640
641 CHECK_OUTPUT(stream, "<a");
642
643 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
644 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
645
646 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, NULL);
647 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
648
649 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
650 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
651
652 IStream_Release(stream);
653 IXmlWriter_Release(writer);
654
655 /* WriteElementString */
656 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
657 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
658
659 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
660 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
661
662 stream = writer_set_output(writer);
663
664 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
665 ok(hr == S_OK, "got 0x%08x\n", hr);
666
667 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
668 ok(hr == S_OK, "got 0x%08x\n", hr);
669
670 hr = IXmlWriter_Flush(writer);
671 ok(hr == S_OK, "got 0x%08x\n", hr);
672
673 CHECK_OUTPUT(stream, str);
674
675 IStream_Release(stream);
676 IXmlWriter_Release(writer);
677 }
678
679 static void test_writeendelement(void)
680 {
681 static const WCHAR aW[] = {'a',0};
682 static const WCHAR bW[] = {'b',0};
683 IXmlWriter *writer;
684 IStream *stream;
685 HRESULT hr;
686
687 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
688 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
689
690 stream = writer_set_output(writer);
691
692 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
693 ok(hr == S_OK, "got 0x%08x\n", hr);
694
695 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
696 ok(hr == S_OK, "got 0x%08x\n", hr);
697
698 hr = IXmlWriter_WriteEndElement(writer);
699 ok(hr == S_OK, "got 0x%08x\n", hr);
700
701 hr = IXmlWriter_WriteEndElement(writer);
702 ok(hr == S_OK, "got 0x%08x\n", hr);
703
704 hr = IXmlWriter_Flush(writer);
705 ok(hr == S_OK, "got 0x%08x\n", hr);
706
707 CHECK_OUTPUT(stream, "<a><b /></a>");
708
709 IXmlWriter_Release(writer);
710 IStream_Release(stream);
711 }
712
713 static void test_writeenddocument(void)
714 {
715 static const WCHAR aW[] = {'a',0};
716 static const WCHAR bW[] = {'b',0};
717 IXmlWriter *writer;
718 IStream *stream;
719 HGLOBAL hglobal;
720 HRESULT hr;
721 char *ptr;
722
723 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
724 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
725
726 hr = IXmlWriter_WriteEndDocument(writer);
727 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
728
729 stream = writer_set_output(writer);
730
731 /* WriteEndDocument resets it to initial state */
732 hr = IXmlWriter_WriteEndDocument(writer);
733 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
734
735 hr = IXmlWriter_WriteEndDocument(writer);
736 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
737
738 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
739 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
740
741 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
742 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
743
744 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
745 ok(hr == S_OK, "got 0x%08x\n", hr);
746
747 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
748 ok(hr == S_OK, "got 0x%08x\n", hr);
749
750 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
751 ok(hr == S_OK, "got 0x%08x\n", hr);
752
753 hr = IXmlWriter_WriteEndDocument(writer);
754 ok(hr == S_OK, "got 0x%08x\n", hr);
755
756 hr = GetHGlobalFromStream(stream, &hglobal);
757 ok(hr == S_OK, "got 0x%08x\n", hr);
758
759 ptr = GlobalLock(hglobal);
760 ok(ptr == NULL, "got %p\n", ptr);
761
762 /* we still need to flush manually, WriteEndDocument doesn't do that */
763 hr = IXmlWriter_Flush(writer);
764 ok(hr == S_OK, "got 0x%08x\n", hr);
765
766 CHECK_OUTPUT(stream, "<a><b /></a>");
767
768 IXmlWriter_Release(writer);
769 IStream_Release(stream);
770 }
771
772 static void test_WriteComment(void)
773 {
774 static const WCHAR closeW[] = {'-','-','>',0};
775 static const WCHAR aW[] = {'a',0};
776 static const WCHAR bW[] = {'b',0};
777 IXmlWriter *writer;
778 IStream *stream;
779 HRESULT hr;
780
781 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
782 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
783
784 hr = IXmlWriter_SetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, TRUE);
785 ok(hr == S_OK, "got 0x%08x\n", hr);
786
787 hr = IXmlWriter_WriteComment(writer, aW);
788 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
789
790 stream = writer_set_output(writer);
791
792 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
793 ok(hr == S_OK, "got 0x%08x\n", hr);
794
795 hr = IXmlWriter_WriteComment(writer, aW);
796 ok(hr == S_OK, "got 0x%08x\n", hr);
797
798 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
799 ok(hr == S_OK, "got 0x%08x\n", hr);
800
801 hr = IXmlWriter_WriteComment(writer, aW);
802 ok(hr == S_OK, "got 0x%08x\n", hr);
803
804 hr = IXmlWriter_WriteComment(writer, NULL);
805 ok(hr == S_OK, "got 0x%08x\n", hr);
806
807 hr = IXmlWriter_WriteComment(writer, closeW);
808 ok(hr == S_OK, "got 0x%08x\n", hr);
809
810 hr = IXmlWriter_Flush(writer);
811 ok(hr == S_OK, "got 0x%08x\n", hr);
812
813 CHECK_OUTPUT(stream, "<!--a--><b><!--a--><!----><!--- ->-->");
814
815 IXmlWriter_Release(writer);
816 IStream_Release(stream);
817 }
818
819 static void test_WriteCData(void)
820 {
821 static const WCHAR closeW[] = {']',']','>',0};
822 static const WCHAR close2W[] = {'a',']',']','>','b',0};
823 static const WCHAR aW[] = {'a',0};
824 static const WCHAR bW[] = {'b',0};
825 IXmlWriter *writer;
826 IStream *stream;
827 HRESULT hr;
828
829 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
830 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
831
832 hr = IXmlWriter_SetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, TRUE);
833 ok(hr == S_OK, "got 0x%08x\n", hr);
834
835 hr = IXmlWriter_WriteCData(writer, aW);
836 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
837
838 stream = writer_set_output(writer);
839
840 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
841 ok(hr == S_OK, "got 0x%08x\n", hr);
842
843 hr = IXmlWriter_WriteCData(writer, aW);
844 ok(hr == S_OK, "got 0x%08x\n", hr);
845
846 hr = IXmlWriter_WriteCData(writer, NULL);
847 ok(hr == S_OK, "got 0x%08x\n", hr);
848
849 hr = IXmlWriter_WriteCData(writer, closeW);
850 ok(hr == S_OK, "got 0x%08x\n", hr);
851
852 hr = IXmlWriter_WriteCData(writer, close2W);
853 ok(hr == S_OK, "got 0x%08x\n", hr);
854
855 hr = IXmlWriter_Flush(writer);
856 ok(hr == S_OK, "got 0x%08x\n", hr);
857
858 CHECK_OUTPUT(stream,
859 "<b>"
860 "<![CDATA[a]]>"
861 "<![CDATA[]]>"
862 "<![CDATA[]]]]>"
863 "<![CDATA[>]]>"
864 "<![CDATA[a]]]]>"
865 "<![CDATA[>b]]>");
866
867 IXmlWriter_Release(writer);
868 IStream_Release(stream);
869 }
870
871 static void test_WriteRaw(void)
872 {
873 static const WCHAR rawW[] = {'a','<',':',0};
874 static const WCHAR aW[] = {'a',0};
875 IXmlWriter *writer;
876 IStream *stream;
877 HRESULT hr;
878
879 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
880 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
881
882 hr = IXmlWriter_WriteRaw(writer, NULL);
883 ok(hr == S_OK, "got 0x%08x\n", hr);
884
885 hr = IXmlWriter_WriteRaw(writer, rawW);
886 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
887
888 stream = writer_set_output(writer);
889
890 hr = IXmlWriter_WriteRaw(writer, NULL);
891 ok(hr == S_OK, "got 0x%08x\n", hr);
892
893 hr = IXmlWriter_WriteRaw(writer, rawW);
894 ok(hr == S_OK, "got 0x%08x\n", hr);
895
896 hr = IXmlWriter_WriteRaw(writer, rawW);
897 ok(hr == S_OK, "got 0x%08x\n", hr);
898
899 hr = IXmlWriter_WriteComment(writer, rawW);
900 ok(hr == S_OK, "got 0x%08x\n", hr);
901
902 hr = IXmlWriter_WriteRaw(writer, rawW);
903 ok(hr == S_OK, "got 0x%08x\n", hr);
904
905 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
906 ok(hr == S_OK, "got 0x%08x\n", hr);
907
908 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
909 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
910
911 hr = IXmlWriter_WriteComment(writer, rawW);
912 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
913
914 hr = IXmlWriter_WriteEndDocument(writer);
915 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
916
917 hr = IXmlWriter_WriteRaw(writer, rawW);
918 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
919
920 hr = IXmlWriter_Flush(writer);
921 ok(hr == S_OK, "got 0x%08x\n", hr);
922
923 CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>a<:a<:<!--a<:-->a<:<a>a</a>");
924
925 IXmlWriter_Release(writer);
926 IStream_Release(stream);
927 }
928
929 static void test_writer_state(void)
930 {
931 static const WCHAR aW[] = {'a',0};
932 IXmlWriter *writer;
933 IStream *stream;
934 HRESULT hr;
935
936 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
937 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
938
939 /* initial state */
940 check_writer_state(writer, E_UNEXPECTED);
941
942 /* set output and call 'wrong' method, WriteEndElement */
943 stream = writer_set_output(writer);
944
945 hr = IXmlWriter_WriteEndElement(writer);
946 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
947
948 check_writer_state(writer, WR_E_INVALIDACTION);
949 IStream_Release(stream);
950
951 /* WriteAttributeString */
952 stream = writer_set_output(writer);
953
954 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
955 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
956
957 check_writer_state(writer, WR_E_INVALIDACTION);
958 IStream_Release(stream);
959
960 /* WriteEndDocument */
961 stream = writer_set_output(writer);
962
963 hr = IXmlWriter_WriteEndDocument(writer);
964 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
965
966 check_writer_state(writer, WR_E_INVALIDACTION);
967 IStream_Release(stream);
968
969 /* WriteFullEndElement */
970 stream = writer_set_output(writer);
971
972 hr = IXmlWriter_WriteFullEndElement(writer);
973 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
974
975 check_writer_state(writer, WR_E_INVALIDACTION);
976 IStream_Release(stream);
977
978 /* WriteCData */
979 stream = writer_set_output(writer);
980
981 hr = IXmlWriter_WriteCData(writer, aW);
982 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
983
984 check_writer_state(writer, WR_E_INVALIDACTION);
985 IStream_Release(stream);
986
987 /* WriteName */
988 stream = writer_set_output(writer);
989
990 hr = IXmlWriter_WriteName(writer, aW);
991 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
992
993 check_writer_state(writer, WR_E_INVALIDACTION);
994 IStream_Release(stream);
995
996 /* WriteNmToken */
997 stream = writer_set_output(writer);
998
999 hr = IXmlWriter_WriteNmToken(writer, aW);
1000 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1001
1002 check_writer_state(writer, WR_E_INVALIDACTION);
1003 IStream_Release(stream);
1004
1005 /* WriteString */
1006 stream = writer_set_output(writer);
1007
1008 hr = IXmlWriter_WriteString(writer, aW);
1009 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1010
1011 check_writer_state(writer, WR_E_INVALIDACTION);
1012 IStream_Release(stream);
1013
1014 IXmlWriter_Release(writer);
1015 }
1016
1017 START_TEST(writer)
1018 {
1019 test_writer_create();
1020 test_writer_state();
1021 test_writeroutput();
1022 test_writestartdocument();
1023 test_writestartelement();
1024 test_writeendelement();
1025 test_flush();
1026 test_omitxmldeclaration();
1027 test_bom();
1028 test_writeenddocument();
1029 test_WriteComment();
1030 test_WriteCData();
1031 test_WriteRaw();
1032 }