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