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