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
35 #include "wine/heap.h"
36 #include "wine/test.h"
37
38 #include "initguid.h"
39 DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
40
41 static const WCHAR aW[] = {'a',0};
42
43 #define EXPECT_REF(obj, ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
_expect_ref(IUnknown * obj,ULONG ref,int line)44 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
45 {
46 ULONG refcount;
47 IUnknown_AddRef(obj);
48 refcount = IUnknown_Release(obj);
49 ok_(__FILE__, line)(refcount == ref, "expected refcount %d, got %d\n", ref, refcount);
50 }
51
check_output_raw(IStream * stream,const void * expected,SIZE_T size,int line)52 static void check_output_raw(IStream *stream, const void *expected, SIZE_T size, int line)
53 {
54 SIZE_T content_size;
55 HGLOBAL hglobal;
56 HRESULT hr;
57 WCHAR *ptr;
58
59 hr = GetHGlobalFromStream(stream, &hglobal);
60 ok_(__FILE__, line)(hr == S_OK, "Failed to get the stream handle, hr %#x.\n", hr);
61
62 content_size = GlobalSize(hglobal);
63 ok_(__FILE__, line)(size == content_size, "Unexpected test output size %ld.\n", content_size);
64 ptr = GlobalLock(hglobal);
65 if (size <= content_size)
66 ok_(__FILE__, line)(!memcmp(expected, ptr, size), "Unexpected output content.\n");
67 if (size != content_size && *ptr == 0xfeff)
68 ok_(__FILE__, line)(0, "Content: %s.\n", wine_dbgstr_wn(ptr, content_size / sizeof(WCHAR)));
69
70 GlobalUnlock(hglobal);
71 }
72
check_output(IStream * stream,const char * expected,BOOL todo,int line)73 static void check_output(IStream *stream, const char *expected, BOOL todo, int line)
74 {
75 int len = strlen(expected), size;
76 HGLOBAL hglobal;
77 HRESULT hr;
78 char *ptr;
79
80 hr = GetHGlobalFromStream(stream, &hglobal);
81 ok_(__FILE__, line)(hr == S_OK, "got 0x%08x\n", hr);
82
83 size = GlobalSize(hglobal);
84 ptr = GlobalLock(hglobal);
85 todo_wine_if(todo)
86 {
87 if (size != len)
88 {
89 ok_(__FILE__, line)(0, "data size mismatch, expected %u, got %u\n", len, size);
90 ok_(__FILE__, line)(0, "got |%s|, expected |%s|\n", ptr, expected);
91 }
92 else
93 ok_(__FILE__, line)(!strncmp(ptr, expected, len), "got |%s|, expected |%s|\n", ptr, expected);
94 }
95 GlobalUnlock(hglobal);
96 }
97 #define CHECK_OUTPUT(stream, expected) check_output(stream, expected, FALSE, __LINE__)
98 #define CHECK_OUTPUT_TODO(stream, expected) check_output(stream, expected, TRUE, __LINE__)
99 #define CHECK_OUTPUT_RAW(stream, expected, size) check_output_raw(stream, expected, size, __LINE__)
100
strdupAtoW(const char * str)101 static WCHAR *strdupAtoW(const char *str)
102 {
103 WCHAR *ret = NULL;
104 DWORD len;
105
106 if (!str) return ret;
107 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
108 ret = heap_alloc(len * sizeof(WCHAR));
109 if (ret)
110 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
111 return ret;
112 }
113
writer_set_property(IXmlWriter * writer,XmlWriterProperty property)114 static void writer_set_property(IXmlWriter *writer, XmlWriterProperty property)
115 {
116 HRESULT hr;
117
118 hr = IXmlWriter_SetProperty(writer, property, TRUE);
119 ok(hr == S_OK, "Failed to set writer property, hr %#x.\n", hr);
120 }
121
122 /* used to test all Write* methods for consistent error state */
check_writer_state(IXmlWriter * writer,HRESULT exp_hr)123 static void check_writer_state(IXmlWriter *writer, HRESULT exp_hr)
124 {
125 static const WCHAR aW[] = {'a',0};
126 HRESULT hr;
127
128 /* FIXME: add WriteAttributes */
129
130 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
131 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
132
133 hr = IXmlWriter_WriteCData(writer, aW);
134 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
135
136 hr = IXmlWriter_WriteCharEntity(writer, aW[0]);
137 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
138
139 hr = IXmlWriter_WriteChars(writer, aW, 1);
140 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
141
142 hr = IXmlWriter_WriteComment(writer, aW);
143 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
144
145 hr = IXmlWriter_WriteDocType(writer, aW, NULL, NULL, NULL);
146 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
147
148 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
149 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
150
151 hr = IXmlWriter_WriteEndDocument(writer);
152 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
153
154 hr = IXmlWriter_WriteEndElement(writer);
155 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
156
157 hr = IXmlWriter_WriteEntityRef(writer, aW);
158 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
159
160 hr = IXmlWriter_WriteFullEndElement(writer);
161 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
162
163 hr = IXmlWriter_WriteName(writer, aW);
164 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
165
166 hr = IXmlWriter_WriteNmToken(writer, aW);
167 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
168
169 /* FIXME: add WriteNode */
170 /* FIXME: add WriteNodeShallow */
171
172 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
173 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
174
175 hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL);
176 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
177
178 hr = IXmlWriter_WriteRaw(writer, aW);
179 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
180
181 hr = IXmlWriter_WriteRawChars(writer, aW, 1);
182 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
183
184 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
185 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
186
187 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
188 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
189
190 hr = IXmlWriter_WriteString(writer, aW);
191 ok(hr == exp_hr, "got 0x%08x, expected 0x%08x\n", hr, exp_hr);
192
193 /* FIXME: add WriteSurrogateCharEntity */
194 /* FIXME: add WriteWhitespace */
195 }
196
writer_set_output(IXmlWriter * writer)197 static IStream *writer_set_output(IXmlWriter *writer)
198 {
199 IStream *stream;
200 HRESULT hr;
201
202 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
203 ok(hr == S_OK, "got 0x%08x\n", hr);
204
205 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
206 ok(hr == S_OK, "got 0x%08x\n", hr);
207
208 return stream;
209 }
210
testoutput_QueryInterface(IUnknown * iface,REFIID riid,void ** obj)211 static HRESULT WINAPI testoutput_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
212 {
213 if (IsEqualGUID(riid, &IID_IUnknown)) {
214 *obj = iface;
215 return S_OK;
216 }
217 else {
218 ok(0, "unknown riid=%s\n", wine_dbgstr_guid(riid));
219 return E_NOINTERFACE;
220 }
221 }
222
testoutput_AddRef(IUnknown * iface)223 static ULONG WINAPI testoutput_AddRef(IUnknown *iface)
224 {
225 return 2;
226 }
227
testoutput_Release(IUnknown * iface)228 static ULONG WINAPI testoutput_Release(IUnknown *iface)
229 {
230 return 1;
231 }
232
233 static const IUnknownVtbl testoutputvtbl = {
234 testoutput_QueryInterface,
235 testoutput_AddRef,
236 testoutput_Release
237 };
238
239 static IUnknown testoutput = { &testoutputvtbl };
240
teststream_QueryInterface(ISequentialStream * iface,REFIID riid,void ** obj)241 static HRESULT WINAPI teststream_QueryInterface(ISequentialStream *iface, REFIID riid, void **obj)
242 {
243 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ISequentialStream))
244 {
245 *obj = iface;
246 return S_OK;
247 }
248
249 *obj = NULL;
250 return E_NOINTERFACE;
251 }
252
teststream_AddRef(ISequentialStream * iface)253 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface)
254 {
255 return 2;
256 }
257
teststream_Release(ISequentialStream * iface)258 static ULONG WINAPI teststream_Release(ISequentialStream *iface)
259 {
260 return 1;
261 }
262
teststream_Read(ISequentialStream * iface,void * pv,ULONG cb,ULONG * pread)263 static HRESULT WINAPI teststream_Read(ISequentialStream *iface, void *pv, ULONG cb, ULONG *pread)
264 {
265 ok(0, "unexpected call\n");
266 return E_NOTIMPL;
267 }
268
269 static ULONG g_write_len;
teststream_Write(ISequentialStream * iface,const void * pv,ULONG cb,ULONG * written)270 static HRESULT WINAPI teststream_Write(ISequentialStream *iface, const void *pv, ULONG cb, ULONG *written)
271 {
272 g_write_len = cb;
273 *written = cb;
274 return S_OK;
275 }
276
277 static const ISequentialStreamVtbl teststreamvtbl =
278 {
279 teststream_QueryInterface,
280 teststream_AddRef,
281 teststream_Release,
282 teststream_Read,
283 teststream_Write
284 };
285
286 static ISequentialStream teststream = { &teststreamvtbl };
287
test_writer_create(void)288 static void test_writer_create(void)
289 {
290 HRESULT hr;
291 IXmlWriter *writer;
292 LONG_PTR value;
293 IUnknown *unk;
294
295 /* crashes native */
296 if (0)
297 {
298 CreateXmlWriter(&IID_IXmlWriter, NULL, NULL);
299 CreateXmlWriter(NULL, (void**)&writer, NULL);
300 }
301
302 hr = CreateXmlWriter(&IID_IStream, (void **)&unk, NULL);
303 ok(hr == E_NOINTERFACE, "got %08x\n", hr);
304
305 hr = CreateXmlWriter(&IID_IUnknown, (void **)&unk, NULL);
306 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
307 hr = IUnknown_QueryInterface(unk, &IID_IXmlWriter, (void **)&writer);
308 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
309 ok(unk == (IUnknown *)writer, "unexpected interface pointer\n");
310 IUnknown_Release(unk);
311 IXmlWriter_Release(writer);
312
313 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
314 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
315
316 /* check default properties values */
317 value = 0;
318 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ByteOrderMark, &value);
319 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
320 ok(value == TRUE, "got %ld\n", value);
321
322 value = TRUE;
323 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_Indent, &value);
324 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
325 ok(value == FALSE, "got %ld\n", value);
326
327 value = TRUE;
328 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_OmitXmlDeclaration, &value);
329 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
330 ok(value == FALSE, "got %ld\n", value);
331
332 value = XmlConformanceLevel_Auto;
333 hr = IXmlWriter_GetProperty(writer, XmlWriterProperty_ConformanceLevel, &value);
334 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
335 ok(value == XmlConformanceLevel_Document, "got %ld\n", value);
336
337 IXmlWriter_Release(writer);
338 }
339
test_invalid_output_encoding(IXmlWriter * writer,IUnknown * output)340 static void test_invalid_output_encoding(IXmlWriter *writer, IUnknown *output)
341 {
342 HRESULT hr;
343
344 hr = IXmlWriter_SetOutput(writer, output);
345 ok(hr == S_OK, "Failed to set output, hr %#x.\n", hr);
346
347 /* TODO: WriteAttributes */
348
349 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
350 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
351
352 hr = IXmlWriter_WriteCData(writer, aW);
353 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
354
355 hr = IXmlWriter_WriteCharEntity(writer, 0x100);
356 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
357
358 hr = IXmlWriter_WriteChars(writer, aW, 1);
359 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
360
361 hr = IXmlWriter_WriteComment(writer, aW);
362 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
363
364 hr = IXmlWriter_WriteDocType(writer, aW, NULL, NULL, NULL);
365 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
366
367 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL);
368 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
369
370 hr = IXmlWriter_WriteEndDocument(writer);
371 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
372
373 hr = IXmlWriter_WriteEndElement(writer);
374 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
375
376 hr = IXmlWriter_WriteEntityRef(writer, aW);
377 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
378
379 hr = IXmlWriter_WriteFullEndElement(writer);
380 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
381
382 hr = IXmlWriter_WriteName(writer, aW);
383 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
384
385 hr = IXmlWriter_WriteNmToken(writer, aW);
386 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
387
388 /* TODO: WriteNode */
389 /* TODO: WriteNodeShallow */
390
391 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
392 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
393
394 hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL);
395 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
396
397 hr = IXmlWriter_WriteRaw(writer, aW);
398 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
399
400 hr = IXmlWriter_WriteRawChars(writer, aW, 1);
401 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
402
403 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
404 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
405
406 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
407 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
408
409 hr = IXmlWriter_WriteString(writer, aW);
410 ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr);
411
412 /* TODO: WriteSurrogateCharEntity */
413 /* ًُُTODO: WriteWhitespace */
414
415 hr = IXmlWriter_Flush(writer);
416 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
417 }
418
test_writeroutput(void)419 static void test_writeroutput(void)
420 {
421 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
422 static const WCHAR usasciiW[] = {'u','s','-','a','s','c','i','i',0};
423 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
424 static const WCHAR utf16_outputW[] = {0xfeff,'<','a'};
425 IXmlWriterOutput *output;
426 IXmlWriter *writer;
427 IStream *stream;
428 IUnknown *unk;
429 HRESULT hr;
430
431 output = NULL;
432 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, NULL, &output);
433 ok(hr == S_OK, "got %08x\n", hr);
434 EXPECT_REF(output, 1);
435 IUnknown_Release(output);
436
437 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, utf16W, &output);
438 ok(hr == S_OK, "got %08x\n", hr);
439 unk = NULL;
440 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
441 ok(hr == S_OK, "got %08x\n", hr);
442 todo_wine
443 ok(unk != NULL && unk != output, "got %p, output %p\n", unk, output);
444 EXPECT_REF(output, 2);
445 /* releasing 'unk' crashes on native */
446 IUnknown_Release(output);
447 EXPECT_REF(output, 1);
448 IUnknown_Release(output);
449
450 output = NULL;
451 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, ~0u, &output);
452 ok(hr == S_OK, "got %08x\n", hr);
453 IUnknown_Release(output);
454
455 hr = CreateXmlWriterOutputWithEncodingCodePage(&testoutput, NULL, CP_UTF8, &output);
456 ok(hr == S_OK, "got %08x\n", hr);
457 unk = NULL;
458 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&unk);
459 ok(hr == S_OK, "got %08x\n", hr);
460 ok(unk != NULL, "got %p\n", unk);
461 /* releasing 'unk' crashes on native */
462 IUnknown_Release(output);
463 IUnknown_Release(output);
464
465 /* create with us-ascii */
466 output = NULL;
467 hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, usasciiW, &output);
468 ok(hr == S_OK, "got %08x\n", hr);
469 IUnknown_Release(output);
470
471 /* Output with codepage 1200. */
472 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
473 ok(hr == S_OK, "Failed to create writer, hr %#x.\n", hr);
474
475 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
476 ok(hr == S_OK, "Failed to create stream, hr %#x.\n", hr);
477
478 hr = CreateXmlWriterOutputWithEncodingCodePage((IUnknown *)stream, NULL, 1200, &output);
479 ok(hr == S_OK, "Failed to create writer output, hr %#x.\n", hr);
480
481 hr = IXmlWriter_SetOutput(writer, output);
482 ok(hr == S_OK, "Failed to set writer output, hr %#x.\n", hr);
483
484 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
485 ok(hr == S_OK, "Write failed, hr %#x.\n", hr);
486
487 hr = IXmlWriter_Flush(writer);
488 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
489
490 CHECK_OUTPUT_RAW(stream, utf16_outputW, sizeof(utf16_outputW));
491
492 IStream_Release(stream);
493 IUnknown_Release(output);
494
495 /* Create output with meaningless code page value. */
496 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
497 ok(hr == S_OK, "Failed to create stream, hr %#x.\n", hr);
498
499 output = NULL;
500 hr = CreateXmlWriterOutputWithEncodingCodePage((IUnknown *)stream, NULL, ~0u, &output);
501 ok(hr == S_OK, "Failed to create writer output, hr %#x.\n", hr);
502
503 test_invalid_output_encoding(writer, output);
504 CHECK_OUTPUT(stream, "");
505
506 IStream_Release(stream);
507 IUnknown_Release(output);
508
509 /* Same, with invalid encoding name. */
510 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
511 ok(hr == S_OK, "got 0x%08x\n", hr);
512
513 output = NULL;
514 hr = CreateXmlWriterOutputWithEncodingName((IUnknown *)stream, NULL, dummyW, &output);
515 ok(hr == S_OK, "got %08x\n", hr);
516
517 test_invalid_output_encoding(writer, output);
518 CHECK_OUTPUT(stream, "");
519
520 IStream_Release(stream);
521 IUnknown_Release(output);
522
523 IXmlWriter_Release(writer);
524 }
525
test_writestartdocument(void)526 static void test_writestartdocument(void)
527 {
528 static const char fullprolog[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
529 static const char *prologversion2 = "<?xml version=\"1.0\" encoding=\"uS-asCii\"?>";
530 static const char prologversion[] = "<?xml version=\"1.0\"?>";
531 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
532 static const WCHAR usasciiW[] = {'u','S','-','a','s','C','i','i',0};
533 static const WCHAR xmlW[] = {'x','m','l',0};
534 IXmlWriterOutput *output;
535 IXmlWriter *writer;
536 IStream *stream;
537 HRESULT hr;
538
539 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
540 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
541
542 /* output not set */
543 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
544 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
545
546 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
547 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
548
549 hr = IXmlWriter_Flush(writer);
550 ok(hr == S_OK, "got 0x%08x\n", hr);
551
552 stream = writer_set_output(writer);
553
554 /* nothing written yet */
555 hr = IXmlWriter_Flush(writer);
556 ok(hr == S_OK, "got 0x%08x\n", hr);
557
558 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
559 ok(hr == S_OK, "got 0x%08x\n", hr);
560
561 hr = IXmlWriter_Flush(writer);
562 ok(hr == S_OK, "got 0x%08x\n", hr);
563
564 CHECK_OUTPUT(stream, fullprolog);
565
566 /* one more time */
567 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
568 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
569 IStream_Release(stream);
570
571 /* now add PI manually, and try to start a document */
572 stream = writer_set_output(writer);
573
574 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
575 ok(hr == S_OK, "got 0x%08x\n", hr);
576
577 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
578 ok(hr == S_OK, "got 0x%08x\n", hr);
579
580 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
581 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
582
583 /* another attempt to add 'xml' PI */
584 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
585 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
586
587 hr = IXmlWriter_Flush(writer);
588 ok(hr == S_OK, "got 0x%08x\n", hr);
589
590 CHECK_OUTPUT(stream, prologversion);
591
592 IStream_Release(stream);
593 IXmlWriter_Release(writer);
594
595 /* create with us-ascii */
596 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
597 ok(hr == S_OK, "got 0x%08x\n", hr);
598
599 output = NULL;
600 hr = CreateXmlWriterOutputWithEncodingName((IUnknown *)stream, NULL, usasciiW, &output);
601 ok(hr == S_OK, "got %08x\n", hr);
602
603 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
604 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
605
606 hr = IXmlWriter_SetOutput(writer, output);
607 ok(hr == S_OK, "got %08x\n", hr);
608
609 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
610 ok(hr == S_OK, "got 0x%08x\n", hr);
611
612 hr = IXmlWriter_Flush(writer);
613 ok(hr == S_OK, "got 0x%08x\n", hr);
614
615 CHECK_OUTPUT(stream, prologversion2);
616
617 IStream_Release(stream);
618 IXmlWriter_Release(writer);
619 IUnknown_Release(output);
620 }
621
test_flush(void)622 static void test_flush(void)
623 {
624 IXmlWriter *writer;
625 HRESULT hr;
626
627 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
628 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
629
630 hr = IXmlWriter_SetOutput(writer, (IUnknown*)&teststream);
631 ok(hr == S_OK, "got 0x%08x\n", hr);
632
633 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
634 ok(hr == S_OK, "got 0x%08x\n", hr);
635
636 g_write_len = 0;
637 hr = IXmlWriter_Flush(writer);
638 ok(hr == S_OK, "got 0x%08x\n", hr);
639 ok(g_write_len > 0, "got %d\n", g_write_len);
640
641 g_write_len = 1;
642 hr = IXmlWriter_Flush(writer);
643 ok(hr == S_OK, "got 0x%08x\n", hr);
644 ok(g_write_len == 0, "got %d\n", g_write_len);
645
646 /* Release() flushes too */
647 g_write_len = 1;
648 IXmlWriter_Release(writer);
649 ok(g_write_len == 0, "got %d\n", g_write_len);
650 }
651
test_omitxmldeclaration(void)652 static void test_omitxmldeclaration(void)
653 {
654 static const char prologversion[] = "<?xml version=\"1.0\"?>";
655 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
656 static const WCHAR xmlW[] = {'x','m','l',0};
657 IXmlWriter *writer;
658 HGLOBAL hglobal;
659 IStream *stream;
660 HRESULT hr;
661 char *ptr;
662
663 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
664 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
665
666 stream = writer_set_output(writer);
667
668 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
669
670 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
671 ok(hr == S_OK, "got 0x%08x\n", hr);
672
673 hr = IXmlWriter_Flush(writer);
674 ok(hr == S_OK, "got 0x%08x\n", hr);
675
676 hr = GetHGlobalFromStream(stream, &hglobal);
677 ok(hr == S_OK, "got 0x%08x\n", hr);
678
679 ptr = GlobalLock(hglobal);
680 ok(!ptr, "got %p\n", ptr);
681 GlobalUnlock(hglobal);
682
683 /* one more time */
684 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
685 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
686
687 IStream_Release(stream);
688
689 /* now add PI manually, and try to start a document */
690 stream = writer_set_output(writer);
691
692 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
693 ok(hr == S_OK, "got 0x%08x\n", hr);
694
695 hr = IXmlWriter_Flush(writer);
696 ok(hr == S_OK, "got 0x%08x\n", hr);
697
698 CHECK_OUTPUT(stream, prologversion);
699
700 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
701 ok(hr == S_OK, "got 0x%08x\n", hr);
702
703 hr = IXmlWriter_Flush(writer);
704 ok(hr == S_OK, "got 0x%08x\n", hr);
705
706 CHECK_OUTPUT(stream, prologversion);
707
708 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
709 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
710
711 hr = IXmlWriter_Flush(writer);
712 ok(hr == S_OK, "got 0x%08x\n", hr);
713
714 CHECK_OUTPUT(stream, prologversion);
715
716 /* another attempt to add 'xml' PI */
717 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
718 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
719
720 hr = IXmlWriter_Flush(writer);
721 ok(hr == S_OK, "got 0x%08x\n", hr);
722
723 IStream_Release(stream);
724 IXmlWriter_Release(writer);
725 }
726
test_bom(void)727 static void test_bom(void)
728 {
729 static const WCHAR piW[] = {0xfeff,'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>'};
730 static const WCHAR aopenW[] = {0xfeff,'<','a'};
731 static const WCHAR afullW[] = {0xfeff,'<','a',' ','/','>'};
732 static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0};
733 static const WCHAR utf16W[] = {'u','t','f','-','1','6',0};
734 static const WCHAR xmlW[] = {'x','m','l',0};
735 static const WCHAR bomW[] = {0xfeff};
736 IXmlWriterOutput *output;
737 IXmlWriter *writer;
738 IStream *stream;
739 HGLOBAL hglobal;
740 HRESULT hr;
741
742 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
743 ok(hr == S_OK, "got 0x%08x\n", hr);
744
745 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
746 ok(hr == S_OK, "got %08x\n", hr);
747
748 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
749 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
750
751 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
752
753 hr = IXmlWriter_SetOutput(writer, output);
754 ok(hr == S_OK, "got 0x%08x\n", hr);
755
756 /* BOM is on by default */
757 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
758 ok(hr == S_OK, "got 0x%08x\n", hr);
759
760 hr = IXmlWriter_Flush(writer);
761 ok(hr == S_OK, "got 0x%08x\n", hr);
762
763 CHECK_OUTPUT_RAW(stream, bomW, sizeof(bomW));
764
765 IStream_Release(stream);
766 IUnknown_Release(output);
767
768 /* start with PI */
769 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
770 ok(hr == S_OK, "got 0x%08x\n", hr);
771
772 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
773 ok(hr == S_OK, "got %08x\n", hr);
774
775 hr = IXmlWriter_SetOutput(writer, output);
776 ok(hr == S_OK, "got 0x%08x\n", hr);
777
778 hr = IXmlWriter_WriteProcessingInstruction(writer, xmlW, versionW);
779 ok(hr == S_OK, "got 0x%08x\n", hr);
780
781 hr = IXmlWriter_Flush(writer);
782 ok(hr == S_OK, "got 0x%08x\n", hr);
783
784 CHECK_OUTPUT_RAW(stream, piW, sizeof(piW));
785
786 IUnknown_Release(output);
787 IStream_Release(stream);
788
789 /* start with element */
790 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
791 ok(hr == S_OK, "got 0x%08x\n", hr);
792
793 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
794 ok(hr == S_OK, "got %08x\n", hr);
795
796 hr = IXmlWriter_SetOutput(writer, output);
797 ok(hr == S_OK, "got 0x%08x\n", hr);
798
799 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
800 ok(hr == S_OK, "got 0x%08x\n", hr);
801
802 hr = IXmlWriter_Flush(writer);
803 ok(hr == S_OK, "got 0x%08x\n", hr);
804
805 CHECK_OUTPUT_RAW(stream, aopenW, sizeof(aopenW));
806
807 IUnknown_Release(output);
808 IStream_Release(stream);
809
810 /* WriteElementString */
811 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
812 ok(hr == S_OK, "got 0x%08x\n", hr);
813
814 hr = CreateXmlWriterOutputWithEncodingName((IUnknown*)stream, NULL, utf16W, &output);
815 ok(hr == S_OK, "got %08x\n", hr);
816
817 hr = IXmlWriter_SetOutput(writer, output);
818 ok(hr == S_OK, "got 0x%08x\n", hr);
819
820 writer_set_property(writer, XmlWriterProperty_Indent);
821
822 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL);
823 ok(hr == S_OK, "got 0x%08x\n", hr);
824
825 hr = IXmlWriter_Flush(writer);
826 ok(hr == S_OK, "got 0x%08x\n", hr);
827
828 hr = GetHGlobalFromStream(stream, &hglobal);
829 ok(hr == S_OK, "got 0x%08x\n", hr);
830
831 CHECK_OUTPUT_RAW(stream, afullW, sizeof(afullW));
832
833 IUnknown_Release(output);
834 IStream_Release(stream);
835
836 IXmlWriter_Release(writer);
837 }
838
write_start_element(IXmlWriter * writer,const char * prefix,const char * local,const char * uri)839 static HRESULT write_start_element(IXmlWriter *writer, const char *prefix, const char *local,
840 const char *uri)
841 {
842 WCHAR *prefixW, *localW, *uriW;
843 HRESULT hr;
844
845 prefixW = strdupAtoW(prefix);
846 localW = strdupAtoW(local);
847 uriW = strdupAtoW(uri);
848
849 hr = IXmlWriter_WriteStartElement(writer, prefixW, localW, uriW);
850
851 heap_free(prefixW);
852 heap_free(localW);
853 heap_free(uriW);
854
855 return hr;
856 }
857
write_element_string(IXmlWriter * writer,const char * prefix,const char * local,const char * uri,const char * value)858 static HRESULT write_element_string(IXmlWriter *writer, const char *prefix, const char *local,
859 const char *uri, const char *value)
860 {
861 WCHAR *prefixW, *localW, *uriW, *valueW;
862 HRESULT hr;
863
864 prefixW = strdupAtoW(prefix);
865 localW = strdupAtoW(local);
866 uriW = strdupAtoW(uri);
867 valueW = strdupAtoW(value);
868
869 hr = IXmlWriter_WriteElementString(writer, prefixW, localW, uriW, valueW);
870
871 heap_free(prefixW);
872 heap_free(localW);
873 heap_free(uriW);
874 heap_free(valueW);
875
876 return hr;
877 }
878
write_string(IXmlWriter * writer,const char * str)879 static HRESULT write_string(IXmlWriter *writer, const char *str)
880 {
881 WCHAR *strW;
882 HRESULT hr;
883
884 strW = strdupAtoW(str);
885
886 hr = IXmlWriter_WriteString(writer, strW);
887
888 heap_free(strW);
889
890 return hr;
891 }
892
test_WriteStartElement(void)893 static void test_WriteStartElement(void)
894 {
895 static const struct
896 {
897 const char *prefix;
898 const char *local;
899 const char *uri;
900 const char *output;
901 const char *output_partial;
902 HRESULT hr;
903 int todo;
904 int todo_partial;
905 }
906 start_element_tests[] =
907 {
908 { "prefix", "local", "uri", "<prefix:local xmlns:prefix=\"uri\" />", "<prefix:local" },
909 { NULL, "local", "uri", "<local xmlns=\"uri\" />", "<local" },
910 { "", "local", "uri", "<local xmlns=\"uri\" />", "<local" },
911 { "", "local", "uri", "<local xmlns=\"uri\" />", "<local" },
912
913 { "prefix", NULL, NULL, NULL, NULL, E_INVALIDARG },
914 { NULL, NULL, "uri", NULL, NULL, E_INVALIDARG },
915 { NULL, NULL, NULL, NULL, NULL, E_INVALIDARG },
916 { NULL, "prefix:local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
917 { "pre:fix", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
918 { NULL, ":local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
919 { ":", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
920 { NULL, "local", "http://www.w3.org/2000/xmlns/", NULL, NULL, WR_E_XMLNSPREFIXDECLARATION },
921 { "prefix", "local", "http://www.w3.org/2000/xmlns/", NULL, NULL, WR_E_XMLNSURIDECLARATION },
922 };
923 static const WCHAR aW[] = {'a',0};
924 IXmlWriter *writer;
925 IStream *stream;
926 unsigned int i;
927 HRESULT hr;
928
929 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
930 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
931
932 hr = write_start_element(writer, NULL, "a", NULL);
933 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
934
935 stream = writer_set_output(writer);
936
937 hr = write_start_element(writer, NULL, "a", NULL);
938 ok(hr == S_OK, "got 0x%08x\n", hr);
939
940 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
941 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
942
943 hr = IXmlWriter_Flush(writer);
944 ok(hr == S_OK, "got 0x%08x\n", hr);
945
946 CHECK_OUTPUT(stream, "<a");
947
948 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
949 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
950
951 hr = IXmlWriter_WriteStartElement(writer, NULL, NULL, NULL);
952 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
953
954 hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW);
955 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
956
957 IStream_Release(stream);
958 IXmlWriter_Release(writer);
959
960 /* WriteElementString */
961 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
962 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
963
964 hr = write_element_string(writer, NULL, "b", NULL, "value");
965 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
966
967 stream = writer_set_output(writer);
968
969 hr = write_start_element(writer, "prefix", "a", "uri");
970 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
971
972 hr = write_element_string(writer, NULL, "b", NULL, "value");
973 ok(hr == S_OK, "Failed to write element string, hr %#x.\n", hr);
974
975 hr = write_element_string(writer, NULL, "c", NULL, NULL);
976 ok(hr == S_OK, "Failed to write element string, hr %#x.\n", hr);
977
978 hr = write_start_element(writer, NULL, "d", "uri");
979 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
980
981 hr = write_start_element(writer, "", "e", "uri");
982 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
983
984 hr = write_start_element(writer, "prefix2", "f", "uri");
985 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
986
987 hr = IXmlWriter_Flush(writer);
988 ok(hr == S_OK, "got 0x%08x\n", hr);
989
990 CHECK_OUTPUT(stream,
991 "<prefix:a xmlns:prefix=\"uri\">"
992 "<b>value</b>"
993 "<c />"
994 "<prefix:d>"
995 "<e xmlns=\"uri\">"
996 "<prefix2:f");
997
998 IStream_Release(stream);
999
1000 /* WriteStartElement */
1001 for (i = 0; i < ARRAY_SIZE(start_element_tests); ++i)
1002 {
1003 stream = writer_set_output(writer);
1004
1005 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1006
1007 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1008 ok(hr == S_OK, "Failed to start document, hr %#x.\n", hr);
1009
1010 hr = write_start_element(writer, start_element_tests[i].prefix, start_element_tests[i].local,
1011 start_element_tests[i].uri);
1012 ok(hr == start_element_tests[i].hr, "%u: unexpected hr %#x.\n", i, hr);
1013
1014 if (SUCCEEDED(start_element_tests[i].hr))
1015 {
1016 hr = IXmlWriter_Flush(writer);
1017 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1018
1019 check_output(stream, start_element_tests[i].output_partial, start_element_tests[i].todo_partial, __LINE__);
1020
1021 hr = IXmlWriter_WriteEndDocument(writer);
1022 ok(hr == S_OK, "Failed to end document, hr %#x.\n", hr);
1023
1024 hr = IXmlWriter_Flush(writer);
1025 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1026
1027 check_output(stream, start_element_tests[i].output, start_element_tests[i].todo, __LINE__);
1028 }
1029
1030 IStream_Release(stream);
1031 }
1032
1033 IXmlWriter_Release(writer);
1034 }
1035
test_WriteElementString(void)1036 static void test_WriteElementString(void)
1037 {
1038 static const struct
1039 {
1040 const char *prefix;
1041 const char *local;
1042 const char *uri;
1043 const char *value;
1044 const char *output;
1045 HRESULT hr;
1046 int todo;
1047 }
1048 element_string_tests[] =
1049 {
1050 { "prefix", "local", "uri", "value", "<prefix:local xmlns:prefix=\"uri\">value</prefix:local>" },
1051 { NULL, "local", "uri", "value", "<local xmlns=\"uri\">value</local>" },
1052 { "", "local", "uri", "value", "<local xmlns=\"uri\">value</local>" },
1053 { "prefix", "local", "uri", NULL, "<prefix:local xmlns:prefix=\"uri\" />" },
1054 { NULL, "local", "uri", NULL, "<local xmlns=\"uri\" />" },
1055 { "", "local", "uri", NULL, "<local xmlns=\"uri\" />" },
1056 { NULL, "local", NULL, NULL, "<local />" },
1057 { "prefix", "local", "uri", "", "<prefix:local xmlns:prefix=\"uri\"></prefix:local>" },
1058 { NULL, "local", "uri", "", "<local xmlns=\"uri\"></local>" },
1059 { "", "local", "uri", "", "<local xmlns=\"uri\"></local>" },
1060 { NULL, "local", NULL, "", "<local></local>" },
1061 { "", "local", "http://www.w3.org/2000/xmlns/", NULL, "<local xmlns=\"http://www.w3.org/2000/xmlns/\" />" },
1062
1063 { "prefix", NULL, NULL, "value", NULL, E_INVALIDARG },
1064 { NULL, NULL, "uri", "value", NULL, E_INVALIDARG },
1065 { NULL, NULL, NULL, "value", NULL, E_INVALIDARG },
1066 { NULL, "prefix:local", "uri", "value", NULL, WC_E_NAMECHARACTER },
1067 { NULL, ":local", "uri", "value", NULL, WC_E_NAMECHARACTER },
1068 { ":", "local", "uri", "value", NULL, WC_E_NAMECHARACTER },
1069 { "prefix", "local", NULL, "value", NULL, WR_E_NSPREFIXWITHEMPTYNSURI },
1070 { "prefix", "local", "", "value", NULL, WR_E_NSPREFIXWITHEMPTYNSURI },
1071 { NULL, "local", "http://www.w3.org/2000/xmlns/", "value", NULL, WR_E_XMLNSPREFIXDECLARATION },
1072 { "prefix", "local", "http://www.w3.org/2000/xmlns/", "value", NULL, WR_E_XMLNSURIDECLARATION },
1073 };
1074 IXmlWriter *writer;
1075 IStream *stream;
1076 unsigned int i;
1077 HRESULT hr;
1078
1079 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1080 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1081
1082 hr = write_element_string(writer, NULL, "b", NULL, "value");
1083 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1084
1085 stream = writer_set_output(writer);
1086
1087 hr = write_start_element(writer, NULL, "a", NULL);
1088 ok(hr == S_OK, "got 0x%08x\n", hr);
1089
1090 hr = write_element_string(writer, NULL, "b", NULL, "value");
1091 ok(hr == S_OK, "got 0x%08x\n", hr);
1092
1093 hr = write_element_string(writer, NULL, "b", NULL, NULL);
1094 ok(hr == S_OK, "got 0x%08x\n", hr);
1095
1096 hr = write_element_string(writer, "prefix", "b", "uri", NULL);
1097 ok(hr == S_OK, "got 0x%08x\n", hr);
1098
1099 hr = write_start_element(writer, "prefix", "c", "uri");
1100 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
1101
1102 hr = write_element_string(writer, "prefix", "d", NULL, NULL);
1103 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1104
1105 hr = write_element_string(writer, "prefix2", "d", "uri", NULL);
1106 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1107
1108 hr = write_element_string(writer, NULL, "e", "uri", NULL);
1109 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1110
1111 hr = write_element_string(writer, "prefix", "f", "uri2", NULL);
1112 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1113
1114 hr = write_element_string(writer, NULL, "g", "uri3", NULL);
1115 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1116
1117 hr = write_element_string(writer, "prefix", "h", NULL, NULL);
1118 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1119
1120 hr = write_element_string(writer, "prefix_i", "i", NULL, NULL);
1121 ok(hr == WR_E_NSPREFIXWITHEMPTYNSURI, "Failed to write element, hr %#x.\n", hr);
1122
1123 hr = write_element_string(writer, "", "j", "uri", NULL);
1124 ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr);
1125
1126 hr = IXmlWriter_Flush(writer);
1127 ok(hr == S_OK, "got 0x%08x\n", hr);
1128
1129 CHECK_OUTPUT(stream,
1130 "<a><b>value</b><b />"
1131 "<prefix:b xmlns:prefix=\"uri\" />"
1132 "<prefix:c xmlns:prefix=\"uri\">"
1133 "<prefix:d />"
1134 "<prefix2:d xmlns:prefix2=\"uri\" />"
1135 "<prefix:e />"
1136 "<prefix:f xmlns:prefix=\"uri2\" />"
1137 "<g xmlns=\"uri3\" />"
1138 "<prefix:h />"
1139 "<j xmlns=\"uri\" />");
1140
1141 IStream_Release(stream);
1142
1143 for (i = 0; i < ARRAY_SIZE(element_string_tests); ++i)
1144 {
1145 stream = writer_set_output(writer);
1146
1147 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1148
1149 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1150 ok(hr == S_OK, "Failed to start document, hr %#x.\n", hr);
1151
1152 hr = write_element_string(writer, element_string_tests[i].prefix, element_string_tests[i].local,
1153 element_string_tests[i].uri, element_string_tests[i].value);
1154 ok(hr == element_string_tests[i].hr, "%u: unexpected hr %#x.\n", i, hr);
1155
1156 if (SUCCEEDED(element_string_tests[i].hr))
1157 {
1158 hr = IXmlWriter_Flush(writer);
1159 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1160
1161 check_output(stream, element_string_tests[i].output, element_string_tests[i].todo, __LINE__);
1162
1163 hr = IXmlWriter_WriteEndDocument(writer);
1164 ok(hr == S_OK, "Failed to end document, hr %#x.\n", hr);
1165
1166 hr = IXmlWriter_Flush(writer);
1167 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1168
1169 check_output(stream, element_string_tests[i].output, element_string_tests[i].todo, __LINE__);
1170 }
1171
1172 IStream_Release(stream);
1173 }
1174
1175 IXmlWriter_Release(writer);
1176 }
1177
test_WriteEndElement(void)1178 static void test_WriteEndElement(void)
1179 {
1180 IXmlWriter *writer;
1181 IStream *stream;
1182 HRESULT hr;
1183
1184 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1185 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1186
1187 stream = writer_set_output(writer);
1188
1189 hr = write_start_element(writer, NULL, "a", NULL);
1190 ok(hr == S_OK, "got 0x%08x\n", hr);
1191
1192 hr = write_start_element(writer, NULL, "b", NULL);
1193 ok(hr == S_OK, "got 0x%08x\n", hr);
1194
1195 hr = IXmlWriter_WriteEndElement(writer);
1196 ok(hr == S_OK, "got 0x%08x\n", hr);
1197
1198 hr = IXmlWriter_WriteEndElement(writer);
1199 ok(hr == S_OK, "got 0x%08x\n", hr);
1200
1201 hr = IXmlWriter_Flush(writer);
1202 ok(hr == S_OK, "got 0x%08x\n", hr);
1203
1204 CHECK_OUTPUT(stream, "<a><b /></a>");
1205
1206 IXmlWriter_Release(writer);
1207 IStream_Release(stream);
1208 }
1209
test_writeenddocument(void)1210 static void test_writeenddocument(void)
1211 {
1212 static const WCHAR aW[] = {'a',0};
1213 static const WCHAR bW[] = {'b',0};
1214 IXmlWriter *writer;
1215 IStream *stream;
1216 HGLOBAL hglobal;
1217 HRESULT hr;
1218 char *ptr;
1219
1220 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1221 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1222
1223 hr = IXmlWriter_WriteEndDocument(writer);
1224 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1225
1226 stream = writer_set_output(writer);
1227
1228 /* WriteEndDocument resets it to initial state */
1229 hr = IXmlWriter_WriteEndDocument(writer);
1230 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1231
1232 hr = IXmlWriter_WriteEndDocument(writer);
1233 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1234
1235 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1236 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1237
1238 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1239 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1240
1241 hr = IXmlWriter_SetOutput(writer, (IUnknown*)stream);
1242 ok(hr == S_OK, "got 0x%08x\n", hr);
1243
1244 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1245 ok(hr == S_OK, "got 0x%08x\n", hr);
1246
1247 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1248 ok(hr == S_OK, "got 0x%08x\n", hr);
1249
1250 hr = IXmlWriter_WriteEndDocument(writer);
1251 ok(hr == S_OK, "got 0x%08x\n", hr);
1252
1253 hr = GetHGlobalFromStream(stream, &hglobal);
1254 ok(hr == S_OK, "got 0x%08x\n", hr);
1255
1256 ptr = GlobalLock(hglobal);
1257 ok(ptr == NULL, "got %p\n", ptr);
1258
1259 /* we still need to flush manually, WriteEndDocument doesn't do that */
1260 hr = IXmlWriter_Flush(writer);
1261 ok(hr == S_OK, "got 0x%08x\n", hr);
1262
1263 CHECK_OUTPUT(stream, "<a><b /></a>");
1264
1265 IXmlWriter_Release(writer);
1266 IStream_Release(stream);
1267 }
1268
test_WriteComment(void)1269 static void test_WriteComment(void)
1270 {
1271 static const WCHAR closeW[] = {'-','-','>',0};
1272 static const WCHAR aW[] = {'a',0};
1273 static const WCHAR bW[] = {'b',0};
1274 IXmlWriter *writer;
1275 IStream *stream;
1276 HRESULT hr;
1277
1278 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1279 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1280
1281 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1282
1283 hr = IXmlWriter_WriteComment(writer, aW);
1284 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1285
1286 stream = writer_set_output(writer);
1287
1288 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1289 ok(hr == S_OK, "got 0x%08x\n", hr);
1290
1291 hr = IXmlWriter_WriteComment(writer, aW);
1292 ok(hr == S_OK, "got 0x%08x\n", hr);
1293
1294 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1295 ok(hr == S_OK, "got 0x%08x\n", hr);
1296
1297 hr = IXmlWriter_WriteComment(writer, aW);
1298 ok(hr == S_OK, "got 0x%08x\n", hr);
1299
1300 hr = IXmlWriter_WriteComment(writer, NULL);
1301 ok(hr == S_OK, "got 0x%08x\n", hr);
1302
1303 hr = IXmlWriter_WriteComment(writer, closeW);
1304 ok(hr == S_OK, "got 0x%08x\n", hr);
1305
1306 hr = IXmlWriter_Flush(writer);
1307 ok(hr == S_OK, "got 0x%08x\n", hr);
1308
1309 CHECK_OUTPUT(stream, "<!--a--><b><!--a--><!----><!--- ->-->");
1310
1311 IXmlWriter_Release(writer);
1312 IStream_Release(stream);
1313 }
1314
test_WriteCData(void)1315 static void test_WriteCData(void)
1316 {
1317 static const WCHAR closeW[] = {']',']','>',0};
1318 static const WCHAR close2W[] = {'a',']',']','>','b',0};
1319 static const WCHAR aW[] = {'a',0};
1320 static const WCHAR bW[] = {'b',0};
1321 IXmlWriter *writer;
1322 IStream *stream;
1323 HRESULT hr;
1324
1325 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1326 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1327
1328 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1329
1330 hr = IXmlWriter_WriteCData(writer, aW);
1331 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1332
1333 stream = writer_set_output(writer);
1334
1335 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1336 ok(hr == S_OK, "got 0x%08x\n", hr);
1337
1338 hr = IXmlWriter_WriteCData(writer, aW);
1339 ok(hr == S_OK, "got 0x%08x\n", hr);
1340
1341 hr = IXmlWriter_WriteCData(writer, NULL);
1342 ok(hr == S_OK, "got 0x%08x\n", hr);
1343
1344 hr = IXmlWriter_WriteCData(writer, closeW);
1345 ok(hr == S_OK, "got 0x%08x\n", hr);
1346
1347 hr = IXmlWriter_WriteCData(writer, close2W);
1348 ok(hr == S_OK, "got 0x%08x\n", hr);
1349
1350 hr = IXmlWriter_Flush(writer);
1351 ok(hr == S_OK, "got 0x%08x\n", hr);
1352
1353 CHECK_OUTPUT(stream,
1354 "<b>"
1355 "<![CDATA[a]]>"
1356 "<![CDATA[]]>"
1357 "<![CDATA[]]]]>"
1358 "<![CDATA[>]]>"
1359 "<![CDATA[a]]]]>"
1360 "<![CDATA[>b]]>");
1361
1362 IXmlWriter_Release(writer);
1363 IStream_Release(stream);
1364 }
1365
test_WriteRaw(void)1366 static void test_WriteRaw(void)
1367 {
1368 static const WCHAR rawW[] = {'a','<',':',0};
1369 static const WCHAR aW[] = {'a',0};
1370 IXmlWriter *writer;
1371 IStream *stream;
1372 HRESULT hr;
1373
1374 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1375 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1376
1377 hr = IXmlWriter_WriteRaw(writer, NULL);
1378 ok(hr == S_OK, "got 0x%08x\n", hr);
1379
1380 hr = IXmlWriter_WriteRaw(writer, rawW);
1381 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1382
1383 stream = writer_set_output(writer);
1384
1385 hr = IXmlWriter_WriteRaw(writer, NULL);
1386 ok(hr == S_OK, "got 0x%08x\n", hr);
1387
1388 hr = IXmlWriter_WriteRaw(writer, rawW);
1389 ok(hr == S_OK, "got 0x%08x\n", hr);
1390
1391 hr = IXmlWriter_WriteRaw(writer, rawW);
1392 ok(hr == S_OK, "got 0x%08x\n", hr);
1393
1394 hr = IXmlWriter_WriteComment(writer, rawW);
1395 ok(hr == S_OK, "got 0x%08x\n", hr);
1396
1397 hr = IXmlWriter_WriteRaw(writer, rawW);
1398 ok(hr == S_OK, "got 0x%08x\n", hr);
1399
1400 hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, aW);
1401 ok(hr == S_OK, "got 0x%08x\n", hr);
1402
1403 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
1404 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1405
1406 hr = IXmlWriter_WriteComment(writer, rawW);
1407 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1408
1409 hr = IXmlWriter_WriteEndDocument(writer);
1410 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1411
1412 hr = IXmlWriter_WriteRaw(writer, rawW);
1413 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1414
1415 hr = IXmlWriter_Flush(writer);
1416 ok(hr == S_OK, "got 0x%08x\n", hr);
1417
1418 CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>a<:a<:<!--a<:-->a<:<a>a</a>");
1419
1420 IXmlWriter_Release(writer);
1421 IStream_Release(stream);
1422 }
1423
test_writer_state(void)1424 static void test_writer_state(void)
1425 {
1426 static const WCHAR aW[] = {'a',0};
1427 IXmlWriter *writer;
1428 IStream *stream;
1429 HRESULT hr;
1430
1431 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1432 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1433
1434 /* initial state */
1435 check_writer_state(writer, E_UNEXPECTED);
1436
1437 /* set output and call 'wrong' method, WriteEndElement */
1438 stream = writer_set_output(writer);
1439
1440 hr = IXmlWriter_WriteEndElement(writer);
1441 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1442
1443 check_writer_state(writer, WR_E_INVALIDACTION);
1444 IStream_Release(stream);
1445
1446 /* WriteAttributeString */
1447 stream = writer_set_output(writer);
1448
1449 hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW);
1450 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1451
1452 check_writer_state(writer, WR_E_INVALIDACTION);
1453 IStream_Release(stream);
1454
1455 /* WriteEndDocument */
1456 stream = writer_set_output(writer);
1457
1458 hr = IXmlWriter_WriteEndDocument(writer);
1459 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1460
1461 check_writer_state(writer, WR_E_INVALIDACTION);
1462 IStream_Release(stream);
1463
1464 /* WriteFullEndElement */
1465 stream = writer_set_output(writer);
1466
1467 hr = IXmlWriter_WriteFullEndElement(writer);
1468 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1469
1470 check_writer_state(writer, WR_E_INVALIDACTION);
1471 IStream_Release(stream);
1472
1473 /* WriteCData */
1474 stream = writer_set_output(writer);
1475
1476 hr = IXmlWriter_WriteCData(writer, aW);
1477 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1478
1479 check_writer_state(writer, WR_E_INVALIDACTION);
1480 IStream_Release(stream);
1481
1482 /* WriteName */
1483 stream = writer_set_output(writer);
1484
1485 hr = IXmlWriter_WriteName(writer, aW);
1486 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1487
1488 check_writer_state(writer, WR_E_INVALIDACTION);
1489 IStream_Release(stream);
1490
1491 /* WriteNmToken */
1492 stream = writer_set_output(writer);
1493
1494 hr = IXmlWriter_WriteNmToken(writer, aW);
1495 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1496
1497 check_writer_state(writer, WR_E_INVALIDACTION);
1498 IStream_Release(stream);
1499
1500 /* WriteString */
1501 stream = writer_set_output(writer);
1502
1503 hr = IXmlWriter_WriteString(writer, aW);
1504 ok(hr == WR_E_INVALIDACTION, "got 0x%08x\n", hr);
1505
1506 check_writer_state(writer, WR_E_INVALIDACTION);
1507 IStream_Release(stream);
1508
1509 IXmlWriter_Release(writer);
1510 }
1511
test_indentation(void)1512 static void test_indentation(void)
1513 {
1514 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
1515 static const WCHAR aW[] = {'a',0};
1516 static const WCHAR bW[] = {'b',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 stream = writer_set_output(writer);
1525
1526 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1527 writer_set_property(writer, XmlWriterProperty_Indent);
1528
1529 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1530 ok(hr == S_OK, "got 0x%08x\n", hr);
1531
1532 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1533 ok(hr == S_OK, "got 0x%08x\n", hr);
1534
1535 hr = IXmlWriter_WriteComment(writer, commentW);
1536 ok(hr == S_OK, "got 0x%08x\n", hr);
1537
1538 hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
1539 ok(hr == S_OK, "got 0x%08x\n", hr);
1540
1541 hr = IXmlWriter_WriteEndDocument(writer);
1542 ok(hr == S_OK, "got 0x%08x\n", hr);
1543
1544 hr = IXmlWriter_Flush(writer);
1545 ok(hr == S_OK, "got 0x%08x\n", hr);
1546
1547 CHECK_OUTPUT(stream,
1548 "<a>\r\n"
1549 " <!--comment-->\r\n"
1550 " <b />\r\n"
1551 "</a>");
1552
1553 IStream_Release(stream);
1554
1555 /* WriteElementString */
1556 stream = writer_set_output(writer);
1557
1558 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1559 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1560
1561 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
1562 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1563
1564 hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
1565 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1566
1567 hr = IXmlWriter_WriteEndElement(writer);
1568 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1569
1570 hr = IXmlWriter_Flush(writer);
1571 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1572
1573 CHECK_OUTPUT(stream,
1574 "<a>\r\n"
1575 " <b />\r\n"
1576 " <b />\r\n"
1577 "</a>");
1578
1579 IStream_Release(stream);
1580
1581 IXmlWriter_Release(writer);
1582 }
1583
write_attribute_string(IXmlWriter * writer,const char * prefix,const char * local,const char * uri,const char * value)1584 static HRESULT write_attribute_string(IXmlWriter *writer, const char *prefix, const char *local,
1585 const char *uri, const char *value)
1586 {
1587 WCHAR *prefixW, *localW, *uriW, *valueW;
1588 HRESULT hr;
1589
1590 prefixW = strdupAtoW(prefix);
1591 localW = strdupAtoW(local);
1592 uriW = strdupAtoW(uri);
1593 valueW = strdupAtoW(value);
1594
1595 hr = IXmlWriter_WriteAttributeString(writer, prefixW, localW, uriW, valueW);
1596
1597 heap_free(prefixW);
1598 heap_free(localW);
1599 heap_free(uriW);
1600 heap_free(valueW);
1601
1602 return hr;
1603 }
1604
test_WriteAttributeString(void)1605 static void test_WriteAttributeString(void)
1606 {
1607 static const struct
1608 {
1609 const char *prefix;
1610 const char *local;
1611 const char *uri;
1612 const char *value;
1613 const char *output;
1614 const char *output_partial;
1615 HRESULT hr;
1616 int todo;
1617 int todo_partial;
1618 int todo_hr;
1619 }
1620 attribute_tests[] =
1621 {
1622 { NULL, "a", NULL, "b", "<e a=\"b\" />", "<e a=\"b\"" },
1623 { "", "a", NULL, "b", "<e a=\"b\" />", "<e a=\"b\"" },
1624 { NULL, "a", "", "b", "<e a=\"b\" />", "<e a=\"b\"" },
1625 { "", "a", "", "b", "<e a=\"b\" />", "<e a=\"b\"" },
1626 { "prefix", "local", "uri", "b", "<e prefix:local=\"b\" xmlns:prefix=\"uri\" />", "<e prefix:local=\"b\"" },
1627 { NULL, "a", "http://www.w3.org/2000/xmlns/", "defuri", "<e xmlns:a=\"defuri\" />", "<e xmlns:a=\"defuri\"" },
1628 { "xmlns", "a", NULL, "uri", "<e xmlns:a=\"uri\" />", "<e xmlns:a=\"uri\"" },
1629 { "xmlns", "a", "", "uri", "<e xmlns:a=\"uri\" />", "<e xmlns:a=\"uri\"" },
1630 { "prefix", "xmlns", "uri", "value", "<e prefix:xmlns=\"value\" xmlns:prefix=\"uri\" />", "<e prefix:xmlns=\"value\"" },
1631 { "prefix", "xmlns", "uri", NULL, "<e prefix:xmlns=\"\" xmlns:prefix=\"uri\" />", "<e prefix:xmlns=\"\"" },
1632 { "prefix", "xmlns", "uri", "", "<e prefix:xmlns=\"\" xmlns:prefix=\"uri\" />", "<e prefix:xmlns=\"\"" },
1633 { "prefix", "xmlns", NULL, "uri", "<e xmlns=\"uri\" />", "<e xmlns=\"uri\"" },
1634 { "prefix", "xmlns", "", "uri", "<e xmlns=\"uri\" />", "<e xmlns=\"uri\"" },
1635 { "xml", "space", NULL, "preserve", "<e xml:space=\"preserve\" />", "<e xml:space=\"preserve\"" },
1636 { "xml", "space", "", "preserve", "<e xml:space=\"preserve\" />", "<e xml:space=\"preserve\"" },
1637 { "xml", "space", NULL, "default", "<e xml:space=\"default\" />", "<e xml:space=\"default\"" },
1638 { "xml", "space", "", "default", "<e xml:space=\"default\" />", "<e xml:space=\"default\"" },
1639 { "xml", "a", NULL, "value", "<e xml:a=\"value\" />", "<e xml:a=\"value\"" },
1640 { "xml", "a", "", "value", "<e xml:a=\"value\" />", "<e xml:a=\"value\"" },
1641
1642 /* Autogenerated prefix names. */
1643 { NULL, "a", "defuri", NULL, "<e p1:a=\"\" xmlns:p1=\"defuri\" />", "<e p1:a=\"\"", S_OK, 1, 1, 1 },
1644 { NULL, "a", "defuri", "b", "<e p1:a=\"b\" xmlns:p1=\"defuri\" />", "<e p1:a=\"b\"", S_OK, 1, 1, 1 },
1645 { "", "a", "defuri", NULL, "<e p1:a=\"\" xmlns:p1=\"defuri\" />", "<e p1:a=\"\"", S_OK, 1, 1, 1 },
1646 { NULL, "a", "defuri", "", "<e p1:a=\"\" xmlns:p1=\"defuri\" />", "<e p1:a=\"\"", S_OK, 1, 1, 1 },
1647 { "", "a", "defuri", "b", "<e p1:a=\"b\" xmlns:p1=\"defuri\" />", "<e p1:a=\"b\"", S_OK, 1, 1, 1 },
1648
1649 /* Failing cases. */
1650 { NULL, NULL, "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", E_INVALIDARG },
1651 { "", "a", "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", WR_E_XMLNSPREFIXDECLARATION, 1, 1, 1 },
1652 { "", NULL, "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", E_INVALIDARG },
1653 { "", "", "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", E_INVALIDARG, 1, 1, 1 },
1654 { NULL, "", "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", E_INVALIDARG, 1, 1, 1 },
1655 { "prefix", "a", "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", WR_E_XMLNSURIDECLARATION, 1, 1, 1 },
1656 { "prefix", NULL, "http://www.w3.org/2000/xmlns/", "defuri", "<e />", "<e", E_INVALIDARG },
1657 { "prefix", NULL, NULL, "b", "<e />", "<e", E_INVALIDARG },
1658 { "prefix", NULL, "uri", NULL, "<e />", "<e", E_INVALIDARG },
1659 { "xml", NULL, NULL, "value", "<e />", "<e", E_INVALIDARG },
1660 { "xmlns", "a", "defuri", NULL, "<e />", "<e", WR_E_XMLNSPREFIXDECLARATION },
1661 { "xmlns", "a", "b", "uri", "<e />", "<e", WR_E_XMLNSPREFIXDECLARATION },
1662 { NULL, "xmlns", "uri", NULL, "<e />", "<e", WR_E_XMLNSPREFIXDECLARATION, 0, 0, 1 },
1663 { "xmlns", NULL, "uri", NULL, "<e />", "<e", WR_E_XMLNSPREFIXDECLARATION, 0, 0, 1 },
1664 { "pre:fix", "local", "uri", "b", "<e />", "<e", WC_E_NAMECHARACTER },
1665 { "pre:fix", NULL, "uri", "b", "<e />", "<e", E_INVALIDARG },
1666 { "prefix", "lo:cal", "uri", "b", "<e />", "<e", WC_E_NAMECHARACTER },
1667 { "xmlns", NULL, NULL, "uri", "<e />", "<e", WR_E_NSPREFIXDECLARED },
1668 { "xmlns", NULL, "", "uri", "<e />", "<e", WR_E_NSPREFIXDECLARED },
1669 { "xmlns", "", NULL, "uri", "<e />", "<e", WR_E_NSPREFIXDECLARED },
1670 { "xmlns", "", "", "uri", "<e />", "<e", WR_E_NSPREFIXDECLARED },
1671 { "xml", "space", "", "value", "<e />", "<e", WR_E_INVALIDXMLSPACE },
1672 { "xml", "space", NULL, "value", "<e />", "<e", WR_E_INVALIDXMLSPACE },
1673 { "xml", "a", "uri", "value", "<e />", "<e", WR_E_XMLPREFIXDECLARATION },
1674 { "xml", "space", NULL, "preServe", "<e />", "<e", WR_E_INVALIDXMLSPACE },
1675 { "xml", "space", NULL, "defAult", "<e />", "<e", WR_E_INVALIDXMLSPACE },
1676 { "xml", "space", NULL, NULL, "<e />", "<e", WR_E_INVALIDXMLSPACE },
1677 { "xml", "space", NULL, "", "<e />", "<e", WR_E_INVALIDXMLSPACE },
1678 };
1679
1680 IXmlWriter *writer;
1681 IStream *stream;
1682 unsigned int i;
1683 HRESULT hr;
1684
1685 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1686 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1687
1688 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1689
1690 for (i = 0; i < ARRAY_SIZE(attribute_tests); ++i)
1691 {
1692 stream = writer_set_output(writer);
1693
1694 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1695 ok(hr == S_OK, "Failed to start document, hr %#x.\n", hr);
1696
1697 hr = write_start_element(writer, NULL, "e", NULL);
1698 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
1699
1700 hr = write_attribute_string(writer, attribute_tests[i].prefix, attribute_tests[i].local,
1701 attribute_tests[i].uri, attribute_tests[i].value);
1702 todo_wine_if(attribute_tests[i].todo_hr)
1703 ok(hr == attribute_tests[i].hr, "%u: unexpected hr %#x, expected %#x.\n", i, hr, attribute_tests[i].hr);
1704
1705 hr = IXmlWriter_Flush(writer);
1706 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1707
1708 check_output(stream, attribute_tests[i].output_partial, attribute_tests[i].todo_partial, __LINE__);
1709
1710 hr = IXmlWriter_WriteEndDocument(writer);
1711 ok(hr == S_OK, "Failed to end document, hr %#x.\n", hr);
1712
1713 hr = IXmlWriter_Flush(writer);
1714 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1715
1716 check_output(stream, attribute_tests[i].output, attribute_tests[i].todo, __LINE__);
1717 IStream_Release(stream);
1718 }
1719
1720 /* With namespaces */
1721 stream = writer_set_output(writer);
1722
1723 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1724 ok(hr == S_OK, "got 0x%08x\n", hr);
1725
1726 hr = write_start_element(writer, "p", "a", "outeruri");
1727 ok(hr == S_OK, "got 0x%08x\n", hr);
1728
1729 hr = write_attribute_string(writer, "prefix", "local", "uri", "b");
1730 ok(hr == S_OK, "got 0x%08x\n", hr);
1731
1732 hr = write_attribute_string(writer, NULL, "a", NULL, "b");
1733 ok(hr == S_OK, "got 0x%08x\n", hr);
1734
1735 hr = write_attribute_string(writer, "xmlns", "prefix", NULL, "uri");
1736 ok(hr == S_OK, "got 0x%08x\n", hr);
1737
1738 hr = write_attribute_string(writer, "p", "attr", NULL, "value");
1739 ok(hr == S_OK, "Failed to write attribute string, hr %#x.\n", hr);
1740
1741 hr = write_attribute_string(writer, "prefix", "local", NULL, "b");
1742 todo_wine
1743 ok(hr == WR_E_DUPLICATEATTRIBUTE, "got 0x%08x\n", hr);
1744
1745 hr = write_start_element(writer, NULL, "b", NULL);
1746 ok(hr == S_OK, "got 0x%08x\n", hr);
1747
1748 hr = write_attribute_string(writer, NULL, "attr2", "outeruri", "value");
1749 ok(hr == S_OK, "Failed to write attribute string, hr %#x.\n", hr);
1750
1751 hr = write_attribute_string(writer, "pr", "attr3", "outeruri", "value");
1752 ok(hr == S_OK, "Failed to write attribute string, hr %#x.\n", hr);
1753
1754 hr = IXmlWriter_WriteEndDocument(writer);
1755 ok(hr == S_OK, "got 0x%08x\n", hr);
1756
1757 hr = IXmlWriter_Flush(writer);
1758 ok(hr == S_OK, "got 0x%08x\n", hr);
1759
1760 CHECK_OUTPUT_TODO(stream,
1761 "<p:a prefix:local=\"b\" a=\"b\" xmlns:prefix=\"uri\" p:attr=\"value\" xmlns:p=\"outeruri\">"
1762 "<b p:attr2=\"value\" pr:attr3=\"value\" xmlns:pr=\"outeruri\" />"
1763 "</p:a>");
1764
1765 IStream_Release(stream);
1766
1767 /* Define prefix, write attribute with it. */
1768 stream = writer_set_output(writer);
1769
1770 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1771 ok(hr == S_OK, "got 0x%08x\n", hr);
1772
1773 hr = write_start_element(writer, NULL, "e", NULL);
1774 ok(hr == S_OK, "got 0x%08x\n", hr);
1775
1776 hr = write_attribute_string(writer, "xmlns", "prefix", NULL, "uri");
1777 ok(hr == S_OK, "got 0x%08x\n", hr);
1778
1779 hr = write_attribute_string(writer, "prefix", "attr", NULL, "value");
1780 ok(hr == S_OK, "got 0x%08x\n", hr);
1781
1782 hr = IXmlWriter_WriteEndDocument(writer);
1783 ok(hr == S_OK, "got 0x%08x\n", hr);
1784
1785 hr = IXmlWriter_Flush(writer);
1786 ok(hr == S_OK, "got 0x%08x\n", hr);
1787
1788 CHECK_OUTPUT(stream,
1789 "<e xmlns:prefix=\"uri\" prefix:attr=\"value\" />");
1790
1791 IStream_Release(stream);
1792
1793 IXmlWriter_Release(writer);
1794 }
1795
test_WriteFullEndElement(void)1796 static void test_WriteFullEndElement(void)
1797 {
1798 static const WCHAR aW[] = {'a',0};
1799 IXmlWriter *writer;
1800 IStream *stream;
1801 HRESULT hr;
1802
1803 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1804 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1805
1806 /* standalone element */
1807 stream = writer_set_output(writer);
1808
1809 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1810 writer_set_property(writer, XmlWriterProperty_Indent);
1811
1812 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1813 ok(hr == S_OK, "got 0x%08x\n", hr);
1814
1815 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1816 ok(hr == S_OK, "got 0x%08x\n", hr);
1817
1818 hr = IXmlWriter_WriteFullEndElement(writer);
1819 ok(hr == S_OK, "got 0x%08x\n", hr);
1820
1821 hr = IXmlWriter_WriteEndDocument(writer);
1822 ok(hr == S_OK, "got 0x%08x\n", hr);
1823
1824 hr = IXmlWriter_Flush(writer);
1825 ok(hr == S_OK, "got 0x%08x\n", hr);
1826
1827 CHECK_OUTPUT(stream,
1828 "<a></a>");
1829 IStream_Release(stream);
1830
1831 /* nested elements */
1832 stream = writer_set_output(writer);
1833
1834 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1835 writer_set_property(writer, XmlWriterProperty_Indent);
1836
1837 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1838 ok(hr == S_OK, "got 0x%08x\n", hr);
1839
1840 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1841 ok(hr == S_OK, "got 0x%08x\n", hr);
1842
1843 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1844 ok(hr == S_OK, "got 0x%08x\n", hr);
1845
1846 hr = IXmlWriter_WriteFullEndElement(writer);
1847 ok(hr == S_OK, "got 0x%08x\n", hr);
1848
1849 hr = IXmlWriter_WriteEndDocument(writer);
1850 ok(hr == S_OK, "got 0x%08x\n", hr);
1851
1852 hr = IXmlWriter_Flush(writer);
1853 ok(hr == S_OK, "got 0x%08x\n", hr);
1854
1855 CHECK_OUTPUT(stream,
1856 "<a>\r\n"
1857 " <a></a>\r\n"
1858 "</a>");
1859
1860 IXmlWriter_Release(writer);
1861 IStream_Release(stream);
1862 }
1863
test_WriteCharEntity(void)1864 static void test_WriteCharEntity(void)
1865 {
1866 static const WCHAR aW[] = {'a',0};
1867 IXmlWriter *writer;
1868 IStream *stream;
1869 HRESULT hr;
1870
1871 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1872 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1873
1874 /* without indentation */
1875 stream = writer_set_output(writer);
1876
1877 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1878
1879 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1880 ok(hr == S_OK, "got 0x%08x\n", hr);
1881
1882 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1883 ok(hr == S_OK, "got 0x%08x\n", hr);
1884
1885 hr = IXmlWriter_WriteCharEntity(writer, 0x100);
1886 ok(hr == S_OK, "got 0x%08x\n", hr);
1887
1888 hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
1889 ok(hr == S_OK, "got 0x%08x\n", hr);
1890
1891 hr = IXmlWriter_WriteEndDocument(writer);
1892 ok(hr == S_OK, "got 0x%08x\n", hr);
1893
1894 hr = IXmlWriter_Flush(writer);
1895 ok(hr == S_OK, "got 0x%08x\n", hr);
1896
1897 CHECK_OUTPUT(stream,
1898 "<a>Ā<a /></a>");
1899
1900 IXmlWriter_Release(writer);
1901 IStream_Release(stream);
1902 }
1903
test_WriteString(void)1904 static void test_WriteString(void)
1905 {
1906 IXmlWriter *writer;
1907 IStream *stream;
1908 HRESULT hr;
1909
1910 hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
1911 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1912
1913 writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
1914
1915 hr = write_string(writer, "a");
1916 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1917
1918 hr = write_string(writer, NULL);
1919 ok(hr == S_OK, "got 0x%08x\n", hr);
1920
1921 hr = write_string(writer, "");
1922 ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
1923
1924 stream = writer_set_output(writer);
1925
1926 hr = write_start_element(writer, NULL, "b", NULL);
1927 ok(hr == S_OK, "got 0x%08x\n", hr);
1928
1929 hr = write_string(writer, NULL);
1930 ok(hr == S_OK, "got 0x%08x\n", hr);
1931
1932 hr = write_string(writer, "");
1933 ok(hr == S_OK, "got 0x%08x\n", hr);
1934
1935 hr = write_string(writer, "a");
1936 ok(hr == S_OK, "got 0x%08x\n", hr);
1937
1938 /* WriteString automatically escapes markup characters */
1939 hr = write_string(writer, "<&\">=");
1940 ok(hr == S_OK, "got 0x%08x\n", hr);
1941
1942 hr = IXmlWriter_Flush(writer);
1943 ok(hr == S_OK, "got 0x%08x\n", hr);
1944
1945 CHECK_OUTPUT(stream,
1946 "<b>a<&\">=");
1947 IStream_Release(stream);
1948
1949 stream = writer_set_output(writer);
1950
1951 hr = write_start_element(writer, NULL, "b", NULL);
1952 ok(hr == S_OK, "got 0x%08x\n", hr);
1953
1954 hr = write_string(writer, NULL);
1955 ok(hr == S_OK, "got 0x%08x\n", hr);
1956
1957 hr = IXmlWriter_Flush(writer);
1958 ok(hr == S_OK, "got 0x%08x\n", hr);
1959
1960 CHECK_OUTPUT(stream,
1961 "<b");
1962
1963 hr = write_string(writer, "");
1964 ok(hr == S_OK, "got 0x%08x\n", hr);
1965
1966 hr = IXmlWriter_Flush(writer);
1967 ok(hr == S_OK, "got 0x%08x\n", hr);
1968
1969 CHECK_OUTPUT(stream,
1970 "<b>");
1971
1972 IStream_Release(stream);
1973 IXmlWriter_Release(writer);
1974
1975 /* With indentation */
1976 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
1977 ok(hr == S_OK, "Failed to create a writer, hr %#x.\n", hr);
1978
1979 stream = writer_set_output(writer);
1980
1981 writer_set_property(writer, XmlWriterProperty_Indent);
1982
1983 hr = write_start_element(writer, NULL, "a", NULL);
1984 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
1985
1986 hr = write_start_element(writer, NULL, "b", NULL);
1987 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
1988
1989 hr = write_string(writer, "text");
1990 ok(hr == S_OK, "Failed to write a string, hr %#x.\n", hr);
1991
1992 hr = IXmlWriter_Flush(writer);
1993 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
1994
1995 CHECK_OUTPUT(stream,
1996 "<a>\r\n"
1997 " <b>text");
1998
1999 hr = IXmlWriter_WriteFullEndElement(writer);
2000 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2001
2002 hr = IXmlWriter_Flush(writer);
2003 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2004
2005 CHECK_OUTPUT(stream,
2006 "<a>\r\n"
2007 " <b>text</b>");
2008
2009 hr = IXmlWriter_WriteFullEndElement(writer);
2010 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2011
2012 hr = IXmlWriter_Flush(writer);
2013 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2014
2015 CHECK_OUTPUT(stream,
2016 "<a>\r\n"
2017 " <b>text</b>\r\n"
2018 "</a>");
2019
2020 IStream_Release(stream);
2021
2022 stream = writer_set_output(writer);
2023
2024 hr = write_start_element(writer, NULL, "a", NULL);
2025 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
2026
2027 hr = write_start_element(writer, NULL, "b", NULL);
2028 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
2029
2030 hr = IXmlWriter_WriteEndElement(writer);
2031 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2032
2033 hr = IXmlWriter_Flush(writer);
2034 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2035
2036 CHECK_OUTPUT(stream,
2037 "<a>\r\n"
2038 " <b />");
2039
2040 hr = write_start_element(writer, NULL, "c", NULL);
2041 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
2042
2043 hr = write_attribute_string(writer, NULL, "attr", NULL, "value");
2044 ok(hr == S_OK, "Failed to write attribute string, hr %#x.\n", hr);
2045
2046 hr = IXmlWriter_Flush(writer);
2047 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2048
2049 CHECK_OUTPUT(stream,
2050 "<a>\r\n"
2051 " <b />\r\n"
2052 " <c attr=\"value\"");
2053
2054 hr = write_string(writer, "text");
2055 ok(hr == S_OK, "Failed to write a string, hr %#x.\n", hr);
2056
2057 hr = IXmlWriter_Flush(writer);
2058 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2059
2060 CHECK_OUTPUT(stream,
2061 "<a>\r\n"
2062 " <b />\r\n"
2063 " <c attr=\"value\">text");
2064
2065 hr = IXmlWriter_WriteEndElement(writer);
2066 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2067
2068 hr = IXmlWriter_Flush(writer);
2069 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2070
2071 CHECK_OUTPUT(stream,
2072 "<a>\r\n"
2073 " <b />\r\n"
2074 " <c attr=\"value\">text</c>");
2075
2076 hr = write_start_element(writer, NULL, "d", NULL);
2077 ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
2078
2079 hr = write_string(writer, "");
2080 ok(hr == S_OK, "Failed to write a string, hr %#x.\n", hr);
2081
2082 hr = IXmlWriter_WriteEndElement(writer);
2083 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2084
2085 hr = IXmlWriter_Flush(writer);
2086 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2087
2088 CHECK_OUTPUT(stream,
2089 "<a>\r\n"
2090 " <b />\r\n"
2091 " <c attr=\"value\">text</c>\r\n"
2092 " <d></d>");
2093
2094 hr = IXmlWriter_WriteEndElement(writer);
2095 ok(hr == S_OK, "Failed to end element, hr %#x.\n", hr);
2096
2097 hr = IXmlWriter_Flush(writer);
2098 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2099
2100 CHECK_OUTPUT(stream,
2101 "<a>\r\n"
2102 " <b />\r\n"
2103 " <c attr=\"value\">text</c>\r\n"
2104 " <d></d>\r\n"
2105 "</a>");
2106
2107 IXmlWriter_Release(writer);
2108 IStream_Release(stream);
2109 }
2110
write_doctype(IXmlWriter * writer,const char * name,const char * pubid,const char * sysid,const char * subset)2111 static HRESULT write_doctype(IXmlWriter *writer, const char *name, const char *pubid, const char *sysid,
2112 const char *subset)
2113 {
2114 WCHAR *nameW, *pubidW, *sysidW, *subsetW;
2115 HRESULT hr;
2116
2117 nameW = strdupAtoW(name);
2118 pubidW = strdupAtoW(pubid);
2119 sysidW = strdupAtoW(sysid);
2120 subsetW = strdupAtoW(subset);
2121
2122 hr = IXmlWriter_WriteDocType(writer, nameW, pubidW, sysidW, subsetW);
2123
2124 heap_free(nameW);
2125 heap_free(pubidW);
2126 heap_free(sysidW);
2127 heap_free(subsetW);
2128
2129 return hr;
2130 }
2131
test_WriteDocType(void)2132 static void test_WriteDocType(void)
2133 {
2134 static const struct
2135 {
2136 const char *name;
2137 const char *pubid;
2138 const char *sysid;
2139 const char *subset;
2140 const char *output;
2141 }
2142 doctype_tests[] =
2143 {
2144 { "a", "", NULL, NULL, "<!DOCTYPE a PUBLIC \"\" \"\">" },
2145 { "a", NULL, NULL, NULL, "<!DOCTYPE a>" },
2146 { "a", NULL, "", NULL, "<!DOCTYPE a SYSTEM \"\">" },
2147 { "a", "", "", NULL, "<!DOCTYPE a PUBLIC \"\" \"\">" },
2148 { "a", "pubid", "", NULL, "<!DOCTYPE a PUBLIC \"pubid\" \"\">" },
2149 { "a", "pubid", NULL, NULL, "<!DOCTYPE a PUBLIC \"pubid\" \"\">" },
2150 { "a", "", "sysid", NULL, "<!DOCTYPE a PUBLIC \"\" \"sysid\">" },
2151 { "a", NULL, NULL, "", "<!DOCTYPE a []>" },
2152 { "a", NULL, NULL, "subset", "<!DOCTYPE a [subset]>" },
2153 { "a", "", NULL, "subset", "<!DOCTYPE a PUBLIC \"\" \"\" [subset]>" },
2154 { "a", NULL, "", "subset", "<!DOCTYPE a SYSTEM \"\" [subset]>" },
2155 { "a", "", "", "subset", "<!DOCTYPE a PUBLIC \"\" \"\" [subset]>" },
2156 { "a", "pubid", NULL, "subset", "<!DOCTYPE a PUBLIC \"pubid\" \"\" [subset]>" },
2157 { "a", "pubid", "", "subset", "<!DOCTYPE a PUBLIC \"pubid\" \"\" [subset]>" },
2158 { "a", NULL, "sysid", "subset", "<!DOCTYPE a SYSTEM \"sysid\" [subset]>" },
2159 { "a", "", "sysid", "subset", "<!DOCTYPE a PUBLIC \"\" \"sysid\" [subset]>" },
2160 { "a", "pubid", "sysid", "subset", "<!DOCTYPE a PUBLIC \"pubid\" \"sysid\" [subset]>" },
2161 };
2162 static const WCHAR pubidW[] = {'p',0x100,'i','d',0};
2163 static const WCHAR nameW[] = {'-','a',0};
2164 static const WCHAR emptyW[] = { 0 };
2165 IXmlWriter *writer;
2166 IStream *stream;
2167 unsigned int i;
2168 HRESULT hr;
2169
2170 hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL);
2171 ok(hr == S_OK, "Failed to create writer instance, hr %#x.\n", hr);
2172
2173 stream = writer_set_output(writer);
2174
2175 hr = IXmlWriter_WriteDocType(writer, NULL, NULL, NULL, NULL);
2176 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
2177
2178 hr = IXmlWriter_WriteDocType(writer, emptyW, NULL, NULL, NULL);
2179 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
2180
2181 /* Name validation. */
2182 hr = IXmlWriter_WriteDocType(writer, nameW, NULL, NULL, NULL);
2183 ok(hr == WC_E_NAMECHARACTER, "Unexpected hr %#x.\n", hr);
2184
2185 /* Pubid validation. */
2186 hr = IXmlWriter_WriteDocType(writer, aW, pubidW, NULL, NULL);
2187 ok(hr == WC_E_PUBLICID, "Unexpected hr %#x.\n", hr);
2188
2189 IStream_Release(stream);
2190
2191 for (i = 0; i < ARRAY_SIZE(doctype_tests); i++)
2192 {
2193 stream = writer_set_output(writer);
2194
2195 hr = write_doctype(writer, doctype_tests[i].name, doctype_tests[i].pubid, doctype_tests[i].sysid,
2196 doctype_tests[i].subset);
2197 ok(hr == S_OK, "%u: failed to write doctype, hr %#x.\n", i, hr);
2198
2199 hr = IXmlWriter_Flush(writer);
2200 ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
2201
2202 CHECK_OUTPUT(stream, doctype_tests[i].output);
2203
2204 hr = write_doctype(writer, doctype_tests[i].name, doctype_tests[i].pubid, doctype_tests[i].sysid,
2205 doctype_tests[i].subset);
2206 ok(hr == WR_E_INVALIDACTION, "Unexpected hr %#x.\n", hr);
2207
2208 IStream_Release(stream);
2209 }
2210
2211 IXmlWriter_Release(writer);
2212 }
2213
START_TEST(writer)2214 START_TEST(writer)
2215 {
2216 test_writer_create();
2217 test_writer_state();
2218 test_writeroutput();
2219 test_writestartdocument();
2220 test_WriteStartElement();
2221 test_WriteElementString();
2222 test_WriteEndElement();
2223 test_flush();
2224 test_omitxmldeclaration();
2225 test_bom();
2226 test_writeenddocument();
2227 test_WriteComment();
2228 test_WriteCData();
2229 test_WriteRaw();
2230 test_indentation();
2231 test_WriteAttributeString();
2232 test_WriteFullEndElement();
2233 test_WriteCharEntity();
2234 test_WriteString();
2235 test_WriteDocType();
2236 }
2237