[XMLLITE_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / modules / 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 #ifdef __REACTOS__
22 #define CONST_VTABLE
23 #endif
24
25 #define COBJMACROS
26
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
33 #include "xmllite.h"
34 #include "wine/test.h"
35
36 #include "initguid.h"
37 DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
38
39 static const WCHAR aW[] = {'a',0};
40
41 #define EXPECT_REF(obj, ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
42 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
43 {
44 ULONG refcount;
45 IUnknown_AddRef(obj);
46 refcount = IUnknown_Release(obj);
47 ok_(__FILE__, line)(refcount == ref, "expected refcount %d, got %d\n", ref, refcount);
48 }
49
50 static void check_output_raw(IStream *stream, const void *expected, SIZE_T size, int line)
51 {
52 SIZE_T content_size;
53 HGLOBAL hglobal;
54 HRESULT hr;
55 char *ptr;
56
57 hr = GetHGlobalFromStream(stream, &hglobal);
58 ok_(__FILE__, line)(hr == S_OK, "Failed to get the stream handle, hr %#x.\n", hr);
59
60 content_size = GlobalSize(hglobal);
61 ok_(__FILE__, line)(size <= content_size, "Unexpected test output size.\n");
62 ptr = GlobalLock(hglobal);
63 if (size <= content_size)
64 ok_(__FILE__, line)(!memcmp(expected, ptr, size), "Unexpected output content.\n");
65
66 GlobalUnlock(hglobal);
67 }
68
69 static void check_output(IStream *stream, const char *expected, BOOL todo, int line)
70 {
71 int len = strlen(expected), size;
72 HGLOBAL hglobal;
73 HRESULT hr;
74 char *ptr;
75
76 hr = GetHGlobalFromStream(stream, &hglobal);
77 ok_(__FILE__, line)(hr == S_OK, "got 0x%08x\n", hr);
78
79 size = GlobalSize(hglobal);
80 ptr = GlobalLock(hglobal);
81 todo_wine_if(todo)
82 {
83 if (size != len)
84 {
85 ok_(__FILE__, line)(0, "data size mismatch, expected %u, got %u\n", len, size);
86 ok_(__FILE__, line)(0, "got |%s|, expected |%s|\n", ptr, expected);
87 }
88 else
89 ok_(__FILE__, line)(!strncmp(ptr, expected, len), "got |%s|, expected |%s|\n", ptr, expected);
90 }
91 GlobalUnlock(hglobal);
92 }
93 #define CHECK_OUTPUT(stream, expected) check_output(stream, expected, FALSE, __LINE__)
94 #define CHECK_OUTPUT_TODO(stream, expected) check_output(stream, expected, TRUE, __LINE__)
95 #define CHECK_OUTPUT_RAW(stream, expected, size) check_output_raw(stream, expected, size, __LINE__)
96
97 static void writer_set_property(IXmlWriter *writer, XmlWriterProperty property)
98 {
99 HRESULT hr;
100
101 hr = IXmlWriter_SetProperty(writer, property, TRUE);
102 ok(hr == S_OK, "Failed to set writer property, hr %#x.\n", hr);
103 }
104
105 /* used to test all Write* methods for consistent error state */
106 static void check_writer_state(IXmlWriter *writer, HRESULT exp_hr)
107 {
108 static const WCHAR aW[] = {'a',0};
109 HRESULT hr;
110
111 /* FIXME: add WriteAttributes */
112
113 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
114 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
115
116 hr = IXmlWriter_WriteCData(writer, aW);
117 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
118
119 hr = IXmlWriter_WriteCharEntity(writer, aW[0]);
120 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
121
122 hr = IXmlWriter_WriteChars(writer, aW, 1);
123 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
124
125 hr = IXmlWriter_WriteComment(writer, aW);
126 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
127
128 /* FIXME: add WriteDocType */
129
130 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
131 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
132
133 hr = IXmlWriter_WriteEndDocument(writer);
134 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
135
136 hr = IXmlWriter_WriteEndElement(writer);
137 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
138
139 hr = IXmlWriter_WriteEntityRef(writer, aW);
140 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
141
142 hr = IXmlWriter_WriteFullEndElement(writer);
143 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
144
145 hr = IXmlWriter_WriteName(writer, aW);
146 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
147
148 hr = IXmlWriter_WriteNmToken(writer, aW);
149 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
150
151 /* FIXME: add WriteNode */
152 /* FIXME: add WriteNodeShallow */
153
154 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
155 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
156
157 hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL);
158 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
159
160 hr = IXmlWriter_WriteRaw(writer, aW);
161 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
162
163 hr = IXmlWriter_WriteRawChars(writer, aW, 1);
164 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
165
166 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
167 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
168
169 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
170 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
171
172 hr = IXmlWriter_WriteString(writer, aW);
173 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
174
175 /* FIXME: add WriteSurrogateCharEntity */
176 /* FIXME: add WriteWhitespace */
177 }
178
179 static IStream *writer_set_output(IXmlWriter *writer)
180 {
181 IStream *stream;
182 HRESULT hr;
183
184 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
185 ok(hr == S_OK, "got 0x%08x\n", hr);
186
187 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
188 ok(hr == S_OK, "got 0x%08x\n", hr);
189
190 return stream;
191 }
192
193 static HRESULT WINAPI testoutput_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
194 {
195 if (IsEqualGUID(riid, &IID_IUnknown)) {
196 *obj = iface;
197 return S_OK;
198 }
199 else {
200 ok(0, "unknown riid=%s\n", wine_dbgstr_guid(riid));
201 return E_NOINTERFACE;
202 }
203 }
204
205 static ULONG WINAPI testoutput_AddRef(IUnknown *iface)
206 {
207 return 2;
208 }
209
210 static ULONG WINAPI testoutput_Release(IUnknown *iface)
211 {
212 return 1;
213 }
214
215 static const IUnknownVtbl testoutputvtbl = {
216 testoutput_QueryInterface,
217 testoutput_AddRef,
218 testoutput_Release
219 };
220
221 static IUnknown testoutput = { &testoutputvtbl };
222
223 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
224 {
225 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
226 {
227 *obj = iface;
228 return S_OK;
229 }
230
231 *obj = NULL;
232 return E_NOINTERFACE;
233 }
234
235 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
236 {
237 return 2;
238 }
239
240 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
241 {
242 return 1;
243 }
244
245 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
246 {
247 ok(0, "unexpected call\n");
248 return E_NOTIMPL;
249 }
250
251 static ULONG g_write_len;
252 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
253 {
254 g_write_len = cb;
255 *written = cb;
256 return S_OK;
257 }
258
259 static const ISequentialStreamVtbl teststreamvtbl =
260 {
261 teststream_QueryInterface,
262 teststream_AddRef,
263 teststream_Release,
264 teststream_Read,
265 teststream_Write
266 };
267
268 static ISequentialStream teststream = { &teststreamvtbl };
269
270 static void test_writer_create(void)
271 {
272 HRESULT hr;
273 IXmlWriter *writer;
274 LONG_PTR value;
275 IUnknown *unk;
276
277 /* crashes native */
278 if (0)
279 {
280 CreateXmlWriter(&IID_IXmlWriter, NULL, NULL);
281 CreateXmlWriter(NULL, (void**)&writer, NULL);
282 }
283
284 hr = CreateXmlWriter(&IID_IStream, (void **)&unk, NULL);
285 ok(hr == E_NOINTERFACE, "got %08x\n", hr);
286
287 hr = CreateXmlWriter(&IID_IUnknown, (void **)&unk, NULL);
288 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
289 hr = IUnknown_QueryInterface(unk, &IID_IXmlWriter, (void **)&writer);
290 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
291 ok(unk == (IUnknown *)writer, "unexpected interface pointer\n");
292 IUnknown_Release(unk);
293 IXmlWriter_Release(writer);
294
295 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
296 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
297
298 /* check default properties values */
299 value = 0;
300 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ByteOrderMark, &value);
301 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
302 ok(value == TRUE, "got %ld\n", value);
303
304 value = TRUE;
305 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_Indent, &value);
306 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
307 ok(value == FALSE, "got %ld\n", value);
308
309 value = TRUE;
310 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, &value);
311 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
312 ok(value == FALSE, "got %ld\n", value);
313
314 value = XmlConformanceLevel_Auto;
315 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ConformanceLevel, &value);
316 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
317 ok(value == XmlConformanceLevel_Document, "got %ld\n", value);
318
319 IXmlWriter_Release(writer);
320 }
321
322 static void test_invalid_output_encoding(IXmlWriter *writer, IUnknown *output)
323 {
324 HRESULT hr;
325
326 hr = IXmlWriter_SetOutput(writer, output);
327 ok(hr == S_OK, "Failed to set output, hr %#x.\n", hr);
328
329 /* TODO: WriteAttributes */
330
331 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
332 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
333
334 hr = IXmlWriter_WriteCData(writer, aW);
335 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
336
337 hr = IXmlWriter_WriteCharEntity(writer, 0x100);
338 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
339
340 hr = IXmlWriter_WriteChars(writer, aW, 1);
341 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
342
343 hr = IXmlWriter_WriteComment(writer, aW);
344 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
345
346 /* TODO: WriteDocType */
347
348 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL);
349 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
350
351 hr = IXmlWriter_WriteEndDocument(writer);
352 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
353
354 hr = IXmlWriter_WriteEndElement(writer);
355 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
356
357 hr = IXmlWriter_WriteEntityRef(writer, aW);
358 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
359
360 hr = IXmlWriter_WriteFullEndElement(writer);
361 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
362
363 hr = IXmlWriter_WriteName(writer, aW);
364 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
365
366 hr = IXmlWriter_WriteNmToken(writer, aW);
367 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
368
369 /* TODO: WriteNode */
370 /* TODO: WriteNodeShallow */
371
372 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
373 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
374
375 hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL);
376 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
377
378 hr = IXmlWriter_WriteRaw(writer, aW);
379 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
380
381 hr = IXmlWriter_WriteRawChars(writer, aW, 1);
382 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
383
384 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
385 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
386
387 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
388 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
389
390 hr = IXmlWriter_WriteString(writer, aW);
391 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
392
393 /* TODO: WriteSurrogateCharEntity */
394 /* ًُُTODO: WriteWhitespace */
395
396 hr = IXmlWriter_Flush(writer);
397 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
398 }
399
400 static void test_writeroutput(void)
401 {
402 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
403 static const WCHAR usasciiW[] = {'u','s','-','a','s','c','i','i',0};
404 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
405 static const WCHAR utf16_outputW[] = {0xfeff,'<','a'};
406 IXmlWriterOutput *output;
407 IXmlWriter *writer;
408 IStream *stream;
409 IUnknown *unk;
410 HRESULT hr;
411
412 output = NULL;
413 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, NULL, &output);
414 ok(hr == S_OK, "got %08x\n", hr);
415 EXPECT_REF(output, 1);
416 IUnknown_Release(output);
417
418 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, utf16W, &output);
419 ok(hr == S_OK, "got %08x\n", hr);
420 unk = NULL;
421 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
422 ok(hr == S_OK, "got %08x\n", hr);
423 todo_wine
424 ok(unk != NULL && unk != output, "got %p, output %p\n", unk, output);
425 EXPECT_REF(output, 2);
426 /* releasing 'unk' crashes on native */
427 IUnknown_Release(output);
428 EXPECT_REF(output, 1);
429 IUnknown_Release(output);
430
431 output = NULL;
432 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, ~0u, &output);
433 ok(hr == S_OK, "got %08x\n", hr);
434 IUnknown_Release(output);
435
436 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, CP_UTF8, &output);
437 ok(hr == S_OK, "got %08x\n", hr);
438 unk = NULL;
439 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
440 ok(hr == S_OK, "got %08x\n", hr);
441 ok(unk != NULL, "got %p\n", unk);
442 /* releasing 'unk' crashes on native */
443 IUnknown_Release(output);
444 IUnknown_Release(output);
445
446 /* create with us-ascii */
447 output = NULL;
448 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, usasciiW, &output);
449 ok(hr == S_OK, "got %08x\n", hr);
450 IUnknown_Release(output);
451
452 /* Output with codepage 1200. */
453 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
454 ok(hr == S_OK, "Failed to create writer, hr %#x.\n", hr);
455
456 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
457 ok(hr == S_OK, "Failed to create stream, hr %#x.\n", hr);
458
459 hr = CreateXmlWriterOutputWithEncodingCodePage((IUnknown *)stream, NULL, 1200, &output);
460 ok(hr == S_OK, "Failed to create writer output, hr %#x.\n", hr);
461
462 hr = IXmlWriter_SetOutput(writer, output);
463 ok(hr == S_OK, "Failed to set writer output, hr %#x.\n", hr);
464
465 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
466 ok(hr == S_OK, "Write failed, hr %#x.\n", hr);
467
468 hr = IXmlWriter_Flush(writer);
469 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
470
471 CHECK_OUTPUT_RAW(stream, utf16_outputW, sizeof(utf16_outputW));
472
473 IStream_Release(stream);
474
475 /* Create output with meaningless code page value. */
476 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
477 ok(hr == S_OK, "Failed to create stream, hr %#x.\n", hr);
478
479 output = NULL;
480 hr = CreateXmlWriterOutputWithEncodingCodePage((IUnknown *)stream, NULL, ~0u, &output);
481 ok(hr == S_OK, "Failed to create writer output, hr %#x.\n", hr);
482
483 test_invalid_output_encoding(writer, output);
484 CHECK_OUTPUT(stream, "");
485
486 IStream_Release(stream);
487 IUnknown_Release(output);
488
489 /* Same, with invalid encoding name. */
490 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
491 ok(hr == S_OK, "got 0x%08x\n", hr);
492
493 output = NULL;
494 hr = CreateXmlWriterOutputWithEncodingName((IUnknown *)stream, NULL, dummyW, &output);
495 ok(hr == S_OK, "got %08x\n", hr);
496
497 test_invalid_output_encoding(writer, output);
498 CHECK_OUTPUT(stream, "");
499
500 IStream_Release(stream);
501 IUnknown_Release(output);
502
503 IXmlWriter_Release(writer);
504 }
505
506 static void test_writestartdocument(void)
507 {
508 static const char fullprolog[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
509 static const char *prologversion2 = "<?xml version=\"1.0\" encoding=\"uS-asCii\"?>";
510 static const char prologversion[] = "<?xml version=\"1.0\"?>";
511 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
512 static const WCHAR usasciiW[] = {'u','S','-','a','s','C','i','i',0};
513 static const WCHAR xmlW[] = {'x','m','l',0};
514 IXmlWriterOutput *output;
515 IXmlWriter *writer;
516 IStream *stream;
517 HRESULT hr;
518
519 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
520 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
521
522 /* output not set */
523 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
524 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
525
526 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
527 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
528
529 hr = IXmlWriter_Flush(writer);
530 ok(hr == S_OK, "got 0x%08x\n", hr);
531
532 stream = writer_set_output(writer);
533
534 /* nothing written yet */
535 hr = IXmlWriter_Flush(writer);
536 ok(hr == S_OK, "got 0x%08x\n", hr);
537
538 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
539 ok(hr == S_OK, "got 0x%08x\n", hr);
540
541 hr = IXmlWriter_Flush(writer);
542 ok(hr == S_OK, "got 0x%08x\n", hr);
543
544 CHECK_OUTPUT(stream, fullprolog);
545
546 /* one more time */
547 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
548 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
549 IStream_Release(stream);
550
551 /* now add PI manually, and try to start a document */
552 stream = writer_set_output(writer);
553
554 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
555 ok(hr == S_OK, "got 0x%08x\n", hr);
556
557 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
558 ok(hr == S_OK, "got 0x%08x\n", hr);
559
560 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
561 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
562
563 /* another attempt to add 'xml' PI */
564 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
565 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
566
567 hr = IXmlWriter_Flush(writer);
568 ok(hr == S_OK, "got 0x%08x\n", hr);
569
570 CHECK_OUTPUT(stream, prologversion);
571
572 IStream_Release(stream);
573 IXmlWriter_Release(writer);
574
575 /* create with us-ascii */
576 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
577 ok(hr == S_OK, "got 0x%08x\n", hr);
578
579 output = NULL;
580 hr = CreateXmlWriterOutputWithEncodingName((IUnknown *)stream, NULL, usasciiW, &output);
581 ok(hr == S_OK, "got %08x\n", hr);
582
583 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
584 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
585
586 hr = IXmlWriter_SetOutput(writer, output);
587 ok(hr == S_OK, "got %08x\n", hr);
588
589 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
590 ok(hr == S_OK, "got 0x%08x\n", hr);
591
592 hr = IXmlWriter_Flush(writer);
593 ok(hr == S_OK, "got 0x%08x\n", hr);
594
595 CHECK_OUTPUT(stream, prologversion2);
596
597 IStream_Release(stream);
598 IXmlWriter_Release(writer);
599 IUnknown_Release(output);
600 }
601
602 static void test_flush(void)
603 {
604 IXmlWriter *writer;
605 HRESULT hr;
606
607 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
608 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
609
610 hr = IXmlWriter_SetOutput(writer, (IUnknown*)&teststream);
611 ok(hr == S_OK, "got 0x%08x\n", hr);
612
613 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
614 ok(hr == S_OK, "got 0x%08x\n", hr);
615
616 g_write_len = 0;
617 hr = IXmlWriter_Flush(writer);
618 ok(hr == S_OK, "got 0x%08x\n", hr);
619 ok(g_write_len > 0, "got %d\n", g_write_len);
620
621 g_write_len = 1;
622 hr = IXmlWriter_Flush(writer);
623 ok(hr == S_OK, "got 0x%08x\n", hr);
624 ok(g_write_len == 0, "got %d\n", g_write_len);
625
626 /* Release() flushes too */
627 g_write_len = 1;
628 IXmlWriter_Release(writer);
629 ok(g_write_len == 0, "got %d\n", g_write_len);
630 }
631
632 static void test_omitxmldeclaration(void)
633 {
634 static const char prologversion[] = "<?xml version=\"1.0\"?>";
635 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
636 static const WCHAR xmlW[] = {'x','m','l',0};
637 IXmlWriter *writer;
638 HGLOBAL hglobal;
639 IStream *stream;
640 HRESULT hr;
641 char *ptr;
642
643 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
644 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
645
646 stream = writer_set_output(writer);
647
648 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
649
650 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
651 ok(hr == S_OK, "got 0x%08x\n", hr);
652
653 hr = IXmlWriter_Flush(writer);
654 ok(hr == S_OK, "got 0x%08x\n", hr);
655
656 hr = GetHGlobalFromStream(stream, &hglobal);
657 ok(hr == S_OK, "got 0x%08x\n", hr);
658
659 ptr = GlobalLock(hglobal);
660 ok(!ptr, "got %p\n", ptr);
661 GlobalUnlock(hglobal);
662
663 /* one more time */
664 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
665 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
666
667 IStream_Release(stream);
668
669 /* now add PI manually, and try to start a document */
670 stream = writer_set_output(writer);
671
672 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
673 ok(hr == S_OK, "got 0x%08x\n", hr);
674
675 hr = IXmlWriter_Flush(writer);
676 ok(hr == S_OK, "got 0x%08x\n", hr);
677
678 CHECK_OUTPUT(stream, prologversion);
679
680 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
681 ok(hr == S_OK, "got 0x%08x\n", hr);
682
683 hr = IXmlWriter_Flush(writer);
684 ok(hr == S_OK, "got 0x%08x\n", hr);
685
686 CHECK_OUTPUT(stream, prologversion);
687
688 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
689 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
690
691 hr = IXmlWriter_Flush(writer);
692 ok(hr == S_OK, "got 0x%08x\n", hr);
693
694 CHECK_OUTPUT(stream, prologversion);
695
696 /* another attempt to add 'xml' PI */
697 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
698 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
699
700 hr = IXmlWriter_Flush(writer);
701 ok(hr == S_OK, "got 0x%08x\n", hr);
702
703 IStream_Release(stream);
704 IXmlWriter_Release(writer);
705 }
706
707 static void test_bom(void)
708 {
709 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
710 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
711 static const WCHAR xmlW[] = {'x','m','l',0};
712 IXmlWriterOutput *output;
713 unsigned char *ptr;
714 IXmlWriter *writer;
715 IStream *stream;
716 HGLOBAL hglobal;
717 HRESULT hr;
718
719 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
720 ok(hr == S_OK, "got 0x%08x\n", hr);
721
722 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
723 ok(hr == S_OK, "got %08x\n", hr);
724
725 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
726 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
727
728 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
729
730 hr = IXmlWriter_SetOutput(writer, output);
731 ok(hr == S_OK, "got 0x%08x\n", hr);
732
733 /* BOM is on by default */
734 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
735 ok(hr == S_OK, "got 0x%08x\n", hr);
736
737 hr = IXmlWriter_Flush(writer);
738 ok(hr == S_OK, "got 0x%08x\n", hr);
739
740 hr = GetHGlobalFromStream(stream, &hglobal);
741 ok(hr == S_OK, "got 0x%08x\n", hr);
742
743 ptr = GlobalLock(hglobal);
744 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
745 GlobalUnlock(hglobal);
746
747 IStream_Release(stream);
748 IUnknown_Release(output);
749
750 /* start with PI */
751 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
752 ok(hr == S_OK, "got 0x%08x\n", hr);
753
754 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
755 ok(hr == S_OK, "got %08x\n", hr);
756
757 hr = IXmlWriter_SetOutput(writer, output);
758 ok(hr == S_OK, "got 0x%08x\n", hr);
759
760 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
761 ok(hr == S_OK, "got 0x%08x\n", hr);
762
763 hr = IXmlWriter_Flush(writer);
764 ok(hr == S_OK, "got 0x%08x\n", hr);
765
766 hr = GetHGlobalFromStream(stream, &hglobal);
767 ok(hr == S_OK, "got 0x%08x\n", hr);
768
769 ptr = GlobalLock(hglobal);
770 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
771 GlobalUnlock(hglobal);
772
773 IUnknown_Release(output);
774 IStream_Release(stream);
775
776 /* start with element */
777 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
778 ok(hr == S_OK, "got 0x%08x\n", hr);
779
780 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
781 ok(hr == S_OK, "got %08x\n", hr);
782
783 hr = IXmlWriter_SetOutput(writer, output);
784 ok(hr == S_OK, "got 0x%08x\n", hr);
785
786 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
787 ok(hr == S_OK, "got 0x%08x\n", hr);
788
789 hr = IXmlWriter_Flush(writer);
790 ok(hr == S_OK, "got 0x%08x\n", hr);
791
792 hr = GetHGlobalFromStream(stream, &hglobal);
793 ok(hr == S_OK, "got 0x%08x\n", hr);
794
795 ptr = GlobalLock(hglobal);
796 ok(ptr[0] == 0xff && ptr[1] == 0xfe, "got %x,%x\n", ptr[0], ptr[1]);
797 GlobalUnlock(hglobal);
798
799 IUnknown_Release(output);
800 IStream_Release(stream);
801
802 /* WriteElementString */
803 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
804 ok(hr == S_OK, "got 0x%08x\n", hr);
805
806 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
807 ok(hr == S_OK, "got %08x\n", hr);
808
809 hr = IXmlWriter_SetOutput(writer, output);
810 ok(hr == S_OK, "got 0x%08x\n", hr);
811
812 writer_set_property(writer, XmlWriterProperty_Indent);
813
814 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL);
815 ok(hr == S_OK, "got 0x%08x\n", hr);
816
817 hr = IXmlWriter_Flush(writer);
818 ok(hr == S_OK, "got 0x%08x\n", hr);
819
820 hr = GetHGlobalFromStream(stream, &hglobal);
821 ok(hr == S_OK, "got 0x%08x\n", hr);
822
823 ptr = GlobalLock(hglobal);
824 ok(ptr[0] == 0xff && ptr[1] == 0xfe && ptr[2] == '<', "Unexpected output: %#x,%#x,%#x\n",
825 ptr[0], ptr[1], ptr[2]);
826 GlobalUnlock(hglobal);
827
828 IUnknown_Release(output);
829 IStream_Release(stream);
830
831 IXmlWriter_Release(writer);
832 }
833
834 static void test_writestartelement(void)
835 {
836 static const WCHAR valueW[] = {'v','a','l','u','e',0};
837 static const WCHAR aW[] = {'a',0};
838 static const WCHAR bW[] = {'b',0};
839 IXmlWriter *writer;
840 IStream *stream;
841 HRESULT hr;
842
843 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
844 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
845
846 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
847 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
848
849 stream = writer_set_output(writer);
850
851 hr = IXmlWriter_WriteStartElement(writer, aW, NULL, NULL);
852 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
853
854 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, NULL);
855 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
856
857 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, aW);
858 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
859
860 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
861 ok(hr == S_OK, "got 0x%08x\n", hr);
862
863 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
864 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
865
866 hr = IXmlWriter_Flush(writer);
867 ok(hr == S_OK, "got 0x%08x\n", hr);
868
869 CHECK_OUTPUT(stream, "<a");
870
871 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
872 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
873
874 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, NULL);
875 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
876
877 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
878 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
879
880 IStream_Release(stream);
881 IXmlWriter_Release(writer);
882
883 /* WriteElementString */
884 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
885 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
886
887 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
888 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
889
890 stream = writer_set_output(writer);
891
892 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
893 ok(hr == S_OK, "got 0x%08x\n", hr);
894
895 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
896 ok(hr == S_OK, "got 0x%08x\n", hr);
897
898 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
899 ok(hr == S_OK, "got 0x%08x\n", hr);
900
901 hr = IXmlWriter_Flush(writer);
902 ok(hr == S_OK, "got 0x%08x\n", hr);
903
904 CHECK_OUTPUT(stream,
905 "<a><b>value</b><b />");
906
907 IStream_Release(stream);
908 IXmlWriter_Release(writer);
909 }
910
911 static void test_writeendelement(void)
912 {
913 static const WCHAR aW[] = {'a',0};
914 static const WCHAR bW[] = {'b',0};
915 IXmlWriter *writer;
916 IStream *stream;
917 HRESULT hr;
918
919 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
920 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
921
922 stream = writer_set_output(writer);
923
924 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
925 ok(hr == S_OK, "got 0x%08x\n", hr);
926
927 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
928 ok(hr == S_OK, "got 0x%08x\n", hr);
929
930 hr = IXmlWriter_WriteEndElement(writer);
931 ok(hr == S_OK, "got 0x%08x\n", hr);
932
933 hr = IXmlWriter_WriteEndElement(writer);
934 ok(hr == S_OK, "got 0x%08x\n", hr);
935
936 hr = IXmlWriter_Flush(writer);
937 ok(hr == S_OK, "got 0x%08x\n", hr);
938
939 CHECK_OUTPUT(stream, "<a><b /></a>");
940
941 IXmlWriter_Release(writer);
942 IStream_Release(stream);
943 }
944
945 static void test_writeenddocument(void)
946 {
947 static const WCHAR aW[] = {'a',0};
948 static const WCHAR bW[] = {'b',0};
949 IXmlWriter *writer;
950 IStream *stream;
951 HGLOBAL hglobal;
952 HRESULT hr;
953 char *ptr;
954
955 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
956 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
957
958 hr = IXmlWriter_WriteEndDocument(writer);
959 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
960
961 stream = writer_set_output(writer);
962
963 /* WriteEndDocument resets it to initial state */
964 hr = IXmlWriter_WriteEndDocument(writer);
965 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
966
967 hr = IXmlWriter_WriteEndDocument(writer);
968 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
969
970 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
971 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
972
973 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
974 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
975
976 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
977 ok(hr == S_OK, "got 0x%08x\n", hr);
978
979 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
980 ok(hr == S_OK, "got 0x%08x\n", hr);
981
982 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
983 ok(hr == S_OK, "got 0x%08x\n", hr);
984
985 hr = IXmlWriter_WriteEndDocument(writer);
986 ok(hr == S_OK, "got 0x%08x\n", hr);
987
988 hr = GetHGlobalFromStream(stream, &hglobal);
989 ok(hr == S_OK, "got 0x%08x\n", hr);
990
991 ptr = GlobalLock(hglobal);
992 ok(ptr == NULL, "got %p\n", ptr);
993
994 /* we still need to flush manually, WriteEndDocument doesn't do that */
995 hr = IXmlWriter_Flush(writer);
996 ok(hr == S_OK, "got 0x%08x\n", hr);
997
998 CHECK_OUTPUT(stream, "<a><b /></a>");
999
1000 IXmlWriter_Release(writer);
1001 IStream_Release(stream);
1002 }
1003
1004 static void test_WriteComment(void)
1005 {
1006 static const WCHAR closeW[] = {'-','-','>',0};
1007 static const WCHAR aW[] = {'a',0};
1008 static const WCHAR bW[] = {'b',0};
1009 IXmlWriter *writer;
1010 IStream *stream;
1011 HRESULT hr;
1012
1013 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1014 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1015
1016 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1017
1018 hr = IXmlWriter_WriteComment(writer, aW);
1019 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1020
1021 stream = writer_set_output(writer);
1022
1023 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1024 ok(hr == S_OK, "got 0x%08x\n", hr);
1025
1026 hr = IXmlWriter_WriteComment(writer, aW);
1027 ok(hr == S_OK, "got 0x%08x\n", hr);
1028
1029 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1030 ok(hr == S_OK, "got 0x%08x\n", hr);
1031
1032 hr = IXmlWriter_WriteComment(writer, aW);
1033 ok(hr == S_OK, "got 0x%08x\n", hr);
1034
1035 hr = IXmlWriter_WriteComment(writer, NULL);
1036 ok(hr == S_OK, "got 0x%08x\n", hr);
1037
1038 hr = IXmlWriter_WriteComment(writer, closeW);
1039 ok(hr == S_OK, "got 0x%08x\n", hr);
1040
1041 hr = IXmlWriter_Flush(writer);
1042 ok(hr == S_OK, "got 0x%08x\n", hr);
1043
1044 CHECK_OUTPUT(stream, "<!--a--><b><!--a--><!----><!--- ->-->");
1045
1046 IXmlWriter_Release(writer);
1047 IStream_Release(stream);
1048 }
1049
1050 static void test_WriteCData(void)
1051 {
1052 static const WCHAR closeW[] = {']',']','>',0};
1053 static const WCHAR close2W[] = {'a',']',']','>','b',0};
1054 static const WCHAR aW[] = {'a',0};
1055 static const WCHAR bW[] = {'b',0};
1056 IXmlWriter *writer;
1057 IStream *stream;
1058 HRESULT hr;
1059
1060 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1061 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1062
1063 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1064
1065 hr = IXmlWriter_WriteCData(writer, aW);
1066 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1067
1068 stream = writer_set_output(writer);
1069
1070 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1071 ok(hr == S_OK, "got 0x%08x\n", hr);
1072
1073 hr = IXmlWriter_WriteCData(writer, aW);
1074 ok(hr == S_OK, "got 0x%08x\n", hr);
1075
1076 hr = IXmlWriter_WriteCData(writer, NULL);
1077 ok(hr == S_OK, "got 0x%08x\n", hr);
1078
1079 hr = IXmlWriter_WriteCData(writer, closeW);
1080 ok(hr == S_OK, "got 0x%08x\n", hr);
1081
1082 hr = IXmlWriter_WriteCData(writer, close2W);
1083 ok(hr == S_OK, "got 0x%08x\n", hr);
1084
1085 hr = IXmlWriter_Flush(writer);
1086 ok(hr == S_OK, "got 0x%08x\n", hr);
1087
1088 CHECK_OUTPUT(stream,
1089 "<b>"
1090 "<![CDATA[a]]>"
1091 "<![CDATA[]]>"
1092 "<![CDATA[]]]]>"
1093 "<![CDATA[>]]>"
1094 "<![CDATA[a]]]]>"
1095 "<![CDATA[>b]]>");
1096
1097 IXmlWriter_Release(writer);
1098 IStream_Release(stream);
1099 }
1100
1101 static void test_WriteRaw(void)
1102 {
1103 static const WCHAR rawW[] = {'a','<',':',0};
1104 static const WCHAR aW[] = {'a',0};
1105 IXmlWriter *writer;
1106 IStream *stream;
1107 HRESULT hr;
1108
1109 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1110 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1111
1112 hr = IXmlWriter_WriteRaw(writer, NULL);
1113 ok(hr == S_OK, "got 0x%08x\n", hr);
1114
1115 hr = IXmlWriter_WriteRaw(writer, rawW);
1116 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1117
1118 stream = writer_set_output(writer);
1119
1120 hr = IXmlWriter_WriteRaw(writer, NULL);
1121 ok(hr == S_OK, "got 0x%08x\n", hr);
1122
1123 hr = IXmlWriter_WriteRaw(writer, rawW);
1124 ok(hr == S_OK, "got 0x%08x\n", hr);
1125
1126 hr = IXmlWriter_WriteRaw(writer, rawW);
1127 ok(hr == S_OK, "got 0x%08x\n", hr);
1128
1129 hr = IXmlWriter_WriteComment(writer, rawW);
1130 ok(hr == S_OK, "got 0x%08x\n", hr);
1131
1132 hr = IXmlWriter_WriteRaw(writer, rawW);
1133 ok(hr == S_OK, "got 0x%08x\n", hr);
1134
1135 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
1136 ok(hr == S_OK, "got 0x%08x\n", hr);
1137
1138 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
1139 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1140
1141 hr = IXmlWriter_WriteComment(writer, rawW);
1142 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1143
1144 hr = IXmlWriter_WriteEndDocument(writer);
1145 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1146
1147 hr = IXmlWriter_WriteRaw(writer, rawW);
1148 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1149
1150 hr = IXmlWriter_Flush(writer);
1151 ok(hr == S_OK, "got 0x%08x\n", hr);
1152
1153 CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>a<:a<:<!--a<:-->a<:<a>a</a>");
1154
1155 IXmlWriter_Release(writer);
1156 IStream_Release(stream);
1157 }
1158
1159 static void test_writer_state(void)
1160 {
1161 static const WCHAR aW[] = {'a',0};
1162 IXmlWriter *writer;
1163 IStream *stream;
1164 HRESULT hr;
1165
1166 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1167 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1168
1169 /* initial state */
1170 check_writer_state(writer, E_UNEXPECTED);
1171
1172 /* set output and call 'wrong' method, WriteEndElement */
1173 stream = writer_set_output(writer);
1174
1175 hr = IXmlWriter_WriteEndElement(writer);
1176 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1177
1178 check_writer_state(writer, WR_E_INVALIDACTION);
1179 IStream_Release(stream);
1180
1181 /* WriteAttributeString */
1182 stream = writer_set_output(writer);
1183
1184 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
1185 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1186
1187 check_writer_state(writer, WR_E_INVALIDACTION);
1188 IStream_Release(stream);
1189
1190 /* WriteEndDocument */
1191 stream = writer_set_output(writer);
1192
1193 hr = IXmlWriter_WriteEndDocument(writer);
1194 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1195
1196 check_writer_state(writer, WR_E_INVALIDACTION);
1197 IStream_Release(stream);
1198
1199 /* WriteFullEndElement */
1200 stream = writer_set_output(writer);
1201
1202 hr = IXmlWriter_WriteFullEndElement(writer);
1203 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1204
1205 check_writer_state(writer, WR_E_INVALIDACTION);
1206 IStream_Release(stream);
1207
1208 /* WriteCData */
1209 stream = writer_set_output(writer);
1210
1211 hr = IXmlWriter_WriteCData(writer, aW);
1212 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1213
1214 check_writer_state(writer, WR_E_INVALIDACTION);
1215 IStream_Release(stream);
1216
1217 /* WriteName */
1218 stream = writer_set_output(writer);
1219
1220 hr = IXmlWriter_WriteName(writer, aW);
1221 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1222
1223 check_writer_state(writer, WR_E_INVALIDACTION);
1224 IStream_Release(stream);
1225
1226 /* WriteNmToken */
1227 stream = writer_set_output(writer);
1228
1229 hr = IXmlWriter_WriteNmToken(writer, aW);
1230 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1231
1232 check_writer_state(writer, WR_E_INVALIDACTION);
1233 IStream_Release(stream);
1234
1235 /* WriteString */
1236 stream = writer_set_output(writer);
1237
1238 hr = IXmlWriter_WriteString(writer, aW);
1239 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1240
1241 check_writer_state(writer, WR_E_INVALIDACTION);
1242 IStream_Release(stream);
1243
1244 IXmlWriter_Release(writer);
1245 }
1246
1247 static void test_indentation(void)
1248 {
1249 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
1250 static const WCHAR aW[] = {'a',0};
1251 static const WCHAR bW[] = {'b',0};
1252 IXmlWriter *writer;
1253 IStream *stream;
1254 HRESULT hr;
1255
1256 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1257 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1258
1259 stream = writer_set_output(writer);
1260
1261 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1262 writer_set_property(writer, XmlWriterProperty_Indent);
1263
1264 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1265 ok(hr == S_OK, "got 0x%08x\n", hr);
1266
1267 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1268 ok(hr == S_OK, "got 0x%08x\n", hr);
1269
1270 hr = IXmlWriter_WriteComment(writer, commentW);
1271 ok(hr == S_OK, "got 0x%08x\n", hr);
1272
1273 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1274 ok(hr == S_OK, "got 0x%08x\n", hr);
1275
1276 hr = IXmlWriter_WriteEndDocument(writer);
1277 ok(hr == S_OK, "got 0x%08x\n", hr);
1278
1279 hr = IXmlWriter_Flush(writer);
1280 ok(hr == S_OK, "got 0x%08x\n", hr);
1281
1282 CHECK_OUTPUT(stream,
1283 "<a>\r\n"
1284 " <!--comment-->\r\n"
1285 " <b />\r\n"
1286 "</a>");
1287
1288 IStream_Release(stream);
1289
1290 /* WriteElementString */
1291 stream = writer_set_output(writer);
1292
1293 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1294 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1295
1296 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
1297 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1298
1299 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
1300 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1301
1302 hr = IXmlWriter_WriteEndElement(writer);
1303 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1304
1305 hr = IXmlWriter_Flush(writer);
1306 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1307
1308 CHECK_OUTPUT(stream,
1309 "<a>\r\n"
1310 " <b />\r\n"
1311 " <b />\r\n"
1312 "</a>");
1313
1314 IStream_Release(stream);
1315
1316 IXmlWriter_Release(writer);
1317 }
1318
1319 static void test_WriteAttributeString(void)
1320 {
1321 static const WCHAR prefixW[] = {'p','r','e','f','i','x',0};
1322 static const WCHAR localW[] = {'l','o','c','a','l',0};
1323 static const WCHAR uriW[] = {'u','r','i',0};
1324 static const WCHAR uri2W[] = {'u','r','i','2',0};
1325 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
1326 static const WCHAR aW[] = {'a',0};
1327 static const WCHAR bW[] = {'b',0};
1328 IXmlWriter *writer;
1329 IStream *stream;
1330 HRESULT hr;
1331
1332 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1333 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1334
1335 stream = writer_set_output(writer);
1336
1337 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1338
1339 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1340 ok(hr == S_OK, "got 0x%08x\n", hr);
1341
1342 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1343 ok(hr == S_OK, "got 0x%08x\n", hr);
1344
1345 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, bW);
1346 ok(hr == S_OK, "got 0x%08x\n", hr);
1347
1348 hr = IXmlWriter_WriteEndDocument(writer);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1350
1351 hr = IXmlWriter_Flush(writer);
1352 ok(hr == S_OK, "got 0x%08x\n", hr);
1353
1354 CHECK_OUTPUT(stream,
1355 "<a a=\"b\" />");
1356 IStream_Release(stream);
1357
1358 /* with namespaces */
1359 stream = writer_set_output(writer);
1360
1361 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1362 ok(hr == S_OK, "got 0x%08x\n", hr);
1363
1364 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1365 ok(hr == S_OK, "got 0x%08x\n", hr);
1366
1367 hr = IXmlWriter_WriteAttributeString(writer, aW, NULL, NULL, bW);
1368 todo_wine
1369 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1370
1371 hr = IXmlWriter_WriteAttributeString(writer, prefixW, localW, uriW, bW);
1372 todo_wine
1373 ok(hr == S_OK, "got 0x%08x\n", hr);
1374
1375 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, bW);
1376 ok(hr == S_OK, "got 0x%08x\n", hr);
1377
1378 hr = IXmlWriter_WriteAttributeString(writer, NULL, xmlnsW, uri2W, NULL);
1379 todo_wine
1380 ok(hr == WR_E_XMLNSPREFIXDECLARATION, "got 0x%08x\n", hr);
1381
1382 hr = IXmlWriter_WriteAttributeString(writer, NULL, xmlnsW, NULL, uri2W);
1383 todo_wine
1384 ok(hr == WR_E_NSPREFIXDECLARED, "got 0x%08x\n", hr);
1385
1386 hr = IXmlWriter_WriteAttributeString(writer, prefixW, localW, NULL, bW);
1387 todo_wine
1388 ok(hr == WR_E_DUPLICATEATTRIBUTE, "got 0x%08x\n", hr);
1389
1390 hr = IXmlWriter_WriteEndDocument(writer);
1391 ok(hr == S_OK, "got 0x%08x\n", hr);
1392
1393 hr = IXmlWriter_Flush(writer);
1394 ok(hr == S_OK, "got 0x%08x\n", hr);
1395
1396 CHECK_OUTPUT_TODO(stream,
1397 "<a prefix:local=\"b\" a=\"b\" xmlns:prefix=\"uri\" />");
1398
1399 IXmlWriter_Release(writer);
1400 IStream_Release(stream);
1401 }
1402
1403 static void test_WriteFullEndElement(void)
1404 {
1405 static const WCHAR aW[] = {'a',0};
1406 IXmlWriter *writer;
1407 IStream *stream;
1408 HRESULT hr;
1409
1410 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1411 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1412
1413 /* standalone element */
1414 stream = writer_set_output(writer);
1415
1416 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1417 writer_set_property(writer, XmlWriterProperty_Indent);
1418
1419 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1420 ok(hr == S_OK, "got 0x%08x\n", hr);
1421
1422 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1423 ok(hr == S_OK, "got 0x%08x\n", hr);
1424
1425 hr = IXmlWriter_WriteFullEndElement(writer);
1426 ok(hr == S_OK, "got 0x%08x\n", hr);
1427
1428 hr = IXmlWriter_WriteEndDocument(writer);
1429 ok(hr == S_OK, "got 0x%08x\n", hr);
1430
1431 hr = IXmlWriter_Flush(writer);
1432 ok(hr == S_OK, "got 0x%08x\n", hr);
1433
1434 CHECK_OUTPUT(stream,
1435 "<a></a>");
1436 IStream_Release(stream);
1437
1438 /* nested elements */
1439 stream = writer_set_output(writer);
1440
1441 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1442 writer_set_property(writer, XmlWriterProperty_Indent);
1443
1444 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1445 ok(hr == S_OK, "got 0x%08x\n", hr);
1446
1447 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1448 ok(hr == S_OK, "got 0x%08x\n", hr);
1449
1450 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1451 ok(hr == S_OK, "got 0x%08x\n", hr);
1452
1453 hr = IXmlWriter_WriteFullEndElement(writer);
1454 ok(hr == S_OK, "got 0x%08x\n", hr);
1455
1456 hr = IXmlWriter_WriteEndDocument(writer);
1457 ok(hr == S_OK, "got 0x%08x\n", hr);
1458
1459 hr = IXmlWriter_Flush(writer);
1460 ok(hr == S_OK, "got 0x%08x\n", hr);
1461
1462 CHECK_OUTPUT(stream,
1463 "<a>\r\n"
1464 " <a></a>\r\n"
1465 "</a>");
1466
1467 IXmlWriter_Release(writer);
1468 IStream_Release(stream);
1469 }
1470
1471 static void test_WriteCharEntity(void)
1472 {
1473 static const WCHAR aW[] = {'a',0};
1474 IXmlWriter *writer;
1475 IStream *stream;
1476 HRESULT hr;
1477
1478 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1479 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1480
1481 /* without indentation */
1482 stream = writer_set_output(writer);
1483
1484 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1485
1486 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1487 ok(hr == S_OK, "got 0x%08x\n", hr);
1488
1489 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1490 ok(hr == S_OK, "got 0x%08x\n", hr);
1491
1492 hr = IXmlWriter_WriteCharEntity(writer, 0x100);
1493 ok(hr == S_OK, "got 0x%08x\n", hr);
1494
1495 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1496 ok(hr == S_OK, "got 0x%08x\n", hr);
1497
1498 hr = IXmlWriter_WriteEndDocument(writer);
1499 ok(hr == S_OK, "got 0x%08x\n", hr);
1500
1501 hr = IXmlWriter_Flush(writer);
1502 ok(hr == S_OK, "got 0x%08x\n", hr);
1503
1504 CHECK_OUTPUT(stream,
1505 "<a>&#x100;<a /></a>");
1506
1507 IXmlWriter_Release(writer);
1508 IStream_Release(stream);
1509 }
1510
1511 static void test_WriteString(void)
1512 {
1513 static const WCHAR markupW[] = {'<','&','"','>','=',0};
1514 static const WCHAR aW[] = {'a',0};
1515 static const WCHAR bW[] = {'b',0};
1516 static const WCHAR emptyW[] = {0};
1517 IXmlWriter *writer;
1518 IStream *stream;
1519 HRESULT hr;
1520
1521 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1522 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1523
1524 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1525
1526 hr = IXmlWriter_WriteString(writer, aW);
1527 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1528
1529 hr = IXmlWriter_WriteString(writer, NULL);
1530 ok(hr == S_OK, "got 0x%08x\n", hr);
1531
1532 hr = IXmlWriter_WriteString(writer, emptyW);
1533 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1534
1535 stream = writer_set_output(writer);
1536
1537 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1538 ok(hr == S_OK, "got 0x%08x\n", hr);
1539
1540 hr = IXmlWriter_WriteString(writer, NULL);
1541 ok(hr == S_OK, "got 0x%08x\n", hr);
1542
1543 hr = IXmlWriter_WriteString(writer, emptyW);
1544 ok(hr == S_OK, "got 0x%08x\n", hr);
1545
1546 hr = IXmlWriter_WriteString(writer, aW);
1547 ok(hr == S_OK, "got 0x%08x\n", hr);
1548
1549 /* WriteString automatically escapes markup characters */
1550 hr = IXmlWriter_WriteString(writer, markupW);
1551 ok(hr == S_OK, "got 0x%08x\n", hr);
1552
1553 hr = IXmlWriter_Flush(writer);
1554 ok(hr == S_OK, "got 0x%08x\n", hr);
1555
1556 CHECK_OUTPUT(stream,
1557 "<b>a&lt;&amp;\"&gt;=");
1558 IStream_Release(stream);
1559
1560 stream = writer_set_output(writer);
1561
1562 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1563 ok(hr == S_OK, "got 0x%08x\n", hr);
1564
1565 hr = IXmlWriter_WriteString(writer, NULL);
1566 ok(hr == S_OK, "got 0x%08x\n", hr);
1567
1568 hr = IXmlWriter_Flush(writer);
1569 ok(hr == S_OK, "got 0x%08x\n", hr);
1570
1571 CHECK_OUTPUT(stream,
1572 "<b");
1573
1574 hr = IXmlWriter_WriteString(writer, emptyW);
1575 ok(hr == S_OK, "got 0x%08x\n", hr);
1576
1577 hr = IXmlWriter_Flush(writer);
1578 ok(hr == S_OK, "got 0x%08x\n", hr);
1579
1580 CHECK_OUTPUT(stream,
1581 "<b>");
1582
1583 IXmlWriter_Release(writer);
1584 IStream_Release(stream);
1585 }
1586
1587 START_TEST(writer)
1588 {
1589 test_writer_create();
1590 test_writer_state();
1591 test_writeroutput();
1592 test_writestartdocument();
1593 test_writestartelement();
1594 test_writeendelement();
1595 test_flush();
1596 test_omitxmldeclaration();
1597 test_bom();
1598 test_writeenddocument();
1599 test_WriteComment();
1600 test_WriteCData();
1601 test_WriteRaw();
1602 test_indentation();
1603 test_WriteAttributeString();
1604 test_WriteFullEndElement();
1605 test_WriteCharEntity();
1606 test_WriteString();
1607 }