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__) 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 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 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 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 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 */ 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 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 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 223 static ULONG WINAPI testoutput_AddRef(IUnknown *iface) 224 { 225 return 2; 226 } 227 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 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 253 static ULONG WINAPI teststream_AddRef(ISequentialStream *iface) 254 { 255 return 2; 256 } 257 258 static ULONG WINAPI teststream_Release(ISequentialStream *iface) 259 { 260 return 1; 261 } 262 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; 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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