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