server: Create the initial thread as a separate request.
[wine.git] / dlls / webservices / tests / writer.c
blobe33c38951ed4962336301d85db817035881caba8
1 /*
2 * Copyright 2015 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include "windows.h"
21 #include "rpc.h"
22 #include "webservices.h"
23 #include "wine/test.h"
25 #include <math.h>
26 #ifndef INFINITY
27 static inline float __port_infinity(void)
29 static const unsigned __inf_bytes = 0x7f800000;
30 return *(const float *)&__inf_bytes;
32 #define INFINITY __port_infinity()
33 #endif
35 #ifndef NAN
36 static inline float __port_nan(void)
38 static const unsigned __nan_bytes = 0x7fc00000;
39 return *(const float *)&__nan_bytes;
41 #define NAN __port_nan()
42 #endif
44 static HRESULT set_output( WS_XML_WRITER *writer )
46 WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
47 WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
48 return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
51 static void test_WsCreateWriter(void)
53 HRESULT hr;
54 WS_XML_WRITER *writer;
55 WS_XML_WRITER_PROPERTY prop;
56 ULONG size, max_depth, max_attrs, indent, trim_size, max_size, max_ns;
57 BOOL allow_fragment, write_decl, in_attr;
58 WS_CHARSET charset;
59 WS_BUFFERS buffers;
60 WS_BYTES bytes;
62 hr = WsCreateWriter( NULL, 0, NULL, NULL );
63 ok( hr == E_INVALIDARG, "got %08x\n", hr );
65 writer = NULL;
66 hr = WsCreateWriter( NULL, 0, &writer, NULL );
67 ok( hr == S_OK, "got %08x\n", hr );
68 ok( writer != NULL, "writer not set\n" );
70 /* can't retrieve properties before output is set */
71 max_depth = 0xdeadbeef;
72 size = sizeof(max_depth);
73 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
74 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
75 ok( max_depth == 0xdeadbeef, "max_depth set\n" );
77 hr = set_output( writer );
78 ok( hr == S_OK, "got %08x\n", hr );
80 /* check some defaults */
81 max_depth = 0xdeadbeef;
82 size = sizeof(max_depth);
83 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
84 ok( hr == S_OK, "got %08x\n", hr );
85 ok( max_depth == 32, "got %u\n", max_depth );
87 allow_fragment = TRUE;
88 size = sizeof(allow_fragment);
89 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT, &allow_fragment, size, NULL );
90 ok( hr == S_OK, "got %08x\n", hr );
91 ok( !allow_fragment, "got %d\n", allow_fragment );
93 max_attrs = 0xdeadbeef;
94 size = sizeof(max_attrs);
95 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, size, NULL );
96 ok( hr == S_OK, "got %08x\n", hr );
97 ok( max_attrs == 128, "got %u\n", max_attrs );
99 write_decl = TRUE;
100 size = sizeof(write_decl);
101 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_WRITE_DECLARATION, &write_decl, size, NULL );
102 ok( hr == S_OK, "got %08x\n", hr );
103 ok( !write_decl, "got %d\n", write_decl );
105 indent = 0xdeadbeef;
106 size = sizeof(indent);
107 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INDENT, &indent, size, NULL );
108 ok( hr == S_OK, "got %08x\n", hr );
109 ok( !indent, "got %u\n", indent );
111 trim_size = 0xdeadbeef;
112 size = sizeof(trim_size);
113 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, size, NULL );
114 ok( hr == S_OK, "got %08x\n", hr );
115 ok( trim_size == 4096, "got %u\n", trim_size );
117 charset = 0xdeadbeef;
118 size = sizeof(charset);
119 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_CHARSET, &charset, size, NULL );
120 ok( hr == S_OK, "got %08x\n", hr );
121 ok( charset == WS_CHARSET_UTF8, "got %u\n", charset );
123 buffers.bufferCount = 0xdeadbeef;
124 buffers.buffers = (WS_BYTES *)0xdeadbeef;
125 size = sizeof(buffers);
126 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFERS, &buffers, size, NULL );
127 ok( hr == S_OK, "got %08x\n", hr );
128 ok( !buffers.bufferCount, "got %u\n", buffers.bufferCount );
129 ok( !buffers.buffers, "got %p\n", buffers.buffers );
131 max_size = 0xdeadbeef;
132 size = sizeof(max_size);
133 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, size, NULL );
134 ok( hr == S_OK, "got %08x\n", hr );
135 ok( max_size == 65536, "got %u\n", max_size );
137 bytes.length = 0xdeadbeef;
138 bytes.bytes = (BYTE *)0xdeadbeef;
139 size = sizeof(bytes);
140 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
141 ok( hr == S_OK, "got %08x\n", hr );
142 ok( !bytes.length, "got %u\n", bytes.length );
143 ok( bytes.bytes != NULL, "got %p\n", bytes.bytes );
145 max_size = 0xdeadbeef;
146 size = sizeof(max_size);
147 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, size, NULL );
148 ok( hr == S_OK, "got %08x\n", hr );
149 ok( max_size == 65536, "got %u\n", max_size );
151 bytes.length = 0xdeadbeef;
152 bytes.bytes = (BYTE *)0xdeadbeef;
153 size = sizeof(bytes);
154 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INITIAL_BUFFER, &bytes, size, NULL );
155 ok( hr == S_OK, "got %08x\n", hr );
156 ok( !bytes.length, "got %u\n", bytes.length );
157 ok( !bytes.bytes, "got %p\n", bytes.bytes );
159 max_ns = 0xdeadbeef;
160 size = sizeof(max_ns);
161 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, size, NULL );
162 ok( hr == S_OK, "got %08x\n", hr );
163 ok( max_ns == 32, "got %u\n", max_ns );
164 WsFreeWriter( writer );
166 /* change a property */
167 max_depth = 16;
168 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
169 prop.value = &max_depth;
170 prop.valueSize = sizeof(max_depth);
171 hr = WsCreateWriter( &prop, 1, &writer, NULL );
172 ok( hr == S_OK, "got %08x\n", hr );
174 hr = set_output( writer );
175 ok( hr == S_OK, "got %08x\n", hr );
177 max_depth = 0xdeadbeef;
178 size = sizeof(max_depth);
179 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
180 ok( hr == S_OK, "got %08x\n", hr );
181 ok( max_depth == 16, "got %u\n", max_depth );
182 WsFreeWriter( writer );
184 /* show that some properties are read-only */
185 in_attr = TRUE;
186 prop.id = WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE;
187 prop.value = &in_attr;
188 prop.valueSize = sizeof(in_attr);
189 hr = WsCreateWriter( &prop, 1, &writer, NULL );
190 ok( hr == E_INVALIDARG, "got %08x\n", hr );
192 size = 1;
193 prop.id = WS_XML_WRITER_PROPERTY_BYTES_WRITTEN;
194 prop.value = &size;
195 prop.valueSize = sizeof(size);
196 hr = WsCreateWriter( &prop, 1, &writer, NULL );
197 ok( hr == E_INVALIDARG, "got %08x\n", hr );
199 size = 1;
200 prop.id = WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE;
201 prop.value = &size;
202 prop.valueSize = sizeof(size);
203 hr = WsCreateWriter( &prop, 1, &writer, NULL );
204 ok( hr == E_INVALIDARG, "got %08x\n", hr );
207 static void test_WsCreateXmlBuffer(void)
209 HRESULT hr;
210 WS_HEAP *heap;
211 WS_XML_WRITER *writer;
212 WS_XML_BUFFER *buffer;
213 WS_BYTES bytes;
214 ULONG size;
216 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
217 ok( hr == E_INVALIDARG, "got %08x\n", hr );
219 hr = WsCreateXmlBuffer( NULL, NULL, 0, &buffer, NULL );
220 ok( hr == E_INVALIDARG, "got %08x\n", hr );
222 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
223 ok( hr == S_OK, "got %08x\n", hr );
225 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
226 ok( hr == E_INVALIDARG, "got %08x\n", hr );
228 buffer = NULL;
229 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
230 ok( hr == S_OK, "got %08x\n", hr );
231 ok( buffer != NULL, "buffer not set\n" );
233 hr = WsCreateWriter( NULL, 0, &writer, NULL );
234 ok( hr == S_OK, "got %08x\n", hr );
236 size = sizeof(bytes);
237 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
238 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
240 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
241 ok( hr == S_OK, "got %08x\n", hr );
243 size = sizeof(bytes);
244 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
245 todo_wine ok( hr == E_INVALIDARG, "got %08x\n", hr );
247 WsFreeWriter( writer );
248 WsFreeHeap( heap );
251 static void test_WsSetOutput(void)
253 HRESULT hr;
254 WS_XML_WRITER *writer;
255 WS_XML_WRITER_PROPERTY prop;
256 WS_XML_WRITER_TEXT_ENCODING encoding;
257 WS_XML_WRITER_BUFFER_OUTPUT output;
258 ULONG size, max_depth;
260 hr = WsCreateWriter( NULL, 0, &writer, NULL );
261 ok( hr == S_OK, "got %08x\n", hr );
263 hr = WsSetOutput( NULL, NULL, NULL, NULL, 0, NULL );
264 ok( hr == E_INVALIDARG, "got %08x\n", hr );
266 encoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_TEXT;
267 encoding.charSet = WS_CHARSET_UTF8;
269 output.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
271 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
272 ok( hr == S_OK, "got %08x\n", hr );
274 /* multiple calls are allowed */
275 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
276 ok( hr == S_OK, "got %08x\n", hr );
278 /* writer properties can be set with WsSetOutput */
279 max_depth = 16;
280 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
281 prop.value = &max_depth;
282 prop.valueSize = sizeof(max_depth);
283 hr = WsSetOutput( writer, &encoding.encoding, &output.output, &prop, 1, NULL );
284 ok( hr == S_OK, "got %08x\n", hr );
286 max_depth = 0xdeadbeef;
287 size = sizeof(max_depth);
288 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
289 ok( hr == S_OK, "got %08x\n", hr );
290 ok( max_depth == 16, "got %u\n", max_depth );
291 WsFreeWriter( writer );
294 static void test_WsSetOutputToBuffer(void)
296 HRESULT hr;
297 WS_HEAP *heap;
298 WS_XML_BUFFER *buffer;
299 WS_XML_WRITER *writer;
300 WS_XML_WRITER_PROPERTY prop;
301 ULONG size, max_depth;
303 hr = WsSetOutputToBuffer( NULL, NULL, NULL, 0, NULL );
304 ok( hr == E_INVALIDARG, "got %08x\n", hr );
306 hr = WsCreateWriter( NULL, 0, &writer, NULL );
307 ok( hr == S_OK, "got %08x\n", hr );
309 hr = WsSetOutputToBuffer( writer, NULL, NULL, 0, NULL );
310 ok( hr == E_INVALIDARG, "got %08x\n", hr );
312 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
313 ok( hr == S_OK, "got %08x\n", hr );
315 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
316 ok( hr == S_OK, "got %08x\n", hr );
318 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
319 ok( hr == S_OK, "got %08x\n", hr );
321 /* multiple calls are allowed */
322 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
323 ok( hr == S_OK, "got %08x\n", hr );
325 /* writer properties can be set with WsSetOutputToBuffer */
326 max_depth = 16;
327 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
328 prop.value = &max_depth;
329 prop.valueSize = sizeof(max_depth);
330 hr = WsSetOutputToBuffer( writer, buffer, &prop, 1, NULL );
331 ok( hr == S_OK, "got %08x\n", hr );
333 max_depth = 0xdeadbeef;
334 size = sizeof(max_depth);
335 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
336 ok( hr == S_OK, "got %08x\n", hr );
337 ok( max_depth == 16, "got %u\n", max_depth );
339 WsFreeWriter( writer );
340 WsFreeHeap( heap );
343 static char strbuf[512];
344 static const char *debugstr_bytes( const BYTE *bytes, ULONG len )
346 const BYTE *src = bytes;
347 char *dst = strbuf;
349 while (len)
351 BYTE c = *src++;
352 if (dst - strbuf > sizeof(strbuf) - 7) break;
353 switch (c)
355 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
356 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
357 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
358 default:
359 if (c >= ' ' && c < 127) *dst++ = c;
360 else
362 sprintf( dst, "\\%02x", c );
363 dst += 3;
366 len--;
368 if (len)
370 *dst++ = '.';
371 *dst++ = '.';
372 *dst++ = '.';
374 *dst = 0;
375 return strbuf;
378 static void check_output( WS_XML_WRITER *writer, const char *expected, unsigned int line )
380 WS_BYTES bytes;
381 ULONG size = sizeof(bytes);
382 int len = strlen( expected );
383 HRESULT hr;
385 memset( &bytes, 0, sizeof(bytes) );
386 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
387 ok( hr == S_OK, "%u: got %08x\n", line, hr );
388 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
389 if (bytes.length != len) return;
390 ok( !memcmp( bytes.bytes, expected, len ),
391 "%u: got %s expected %s\n", line, debugstr_bytes(bytes.bytes, bytes.length), expected );
394 static void test_WsWriteStartElement(void)
396 HRESULT hr;
397 WS_XML_WRITER *writer;
398 WS_XML_STRING prefix = {1, (BYTE *)"p"}, ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
399 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"}, empty = {0, NULL};
401 hr = WsCreateWriter( NULL, 0, &writer, NULL );
402 ok( hr == S_OK, "got %08x\n", hr );
404 hr = set_output( writer );
405 ok( hr == S_OK, "got %08x\n", hr );
407 hr = WsWriteStartElement( NULL, &prefix, &localname, &ns, NULL );
408 ok( hr == E_INVALIDARG, "got %08x\n", hr );
410 /* first call to WsWriteStartElement doesn't output anything */
411 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
412 ok( hr == S_OK, "got %08x\n", hr );
413 check_output( writer, "", __LINE__ );
415 /* two ways to close an element */
416 hr = WsWriteEndStartElement( writer, NULL );
417 ok( hr == S_OK, "got %08x\n", hr );
418 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
420 hr = WsWriteEndElement( writer, NULL );
421 ok( hr == S_OK, "got %08x\n", hr );
422 check_output( writer, "<p:a xmlns:p=\"ns\"></p:a>", __LINE__ );
424 hr = set_output( writer );
425 ok( hr == S_OK, "got %08x\n", hr );
427 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
428 ok( hr == S_OK, "got %08x\n", hr );
430 hr = WsWriteEndElement( writer, NULL );
431 ok( hr == S_OK, "got %08x\n", hr );
432 check_output( writer, "<p:a xmlns:p=\"ns\"/>", __LINE__ );
434 /* nested elements */
435 hr = set_output( writer );
436 ok( hr == S_OK, "got %08x\n", hr );
438 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
439 ok( hr == S_OK, "got %08x\n", hr );
440 check_output( writer, "", __LINE__ );
442 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
443 ok( hr == S_OK, "got %08x\n", hr );
444 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
446 hr = WsWriteEndElement( writer, NULL );
447 ok( hr == S_OK, "got %08x\n", hr );
448 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/>", __LINE__ );
450 hr = WsWriteEndElement( writer, NULL );
451 ok( hr == S_OK, "got %08x\n", hr );
452 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/></p:a>", __LINE__ );
454 hr = set_output( writer );
455 ok( hr == S_OK, "got %08x\n", hr );
457 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
458 ok( hr == S_OK, "got %08x\n", hr );
459 check_output( writer, "", __LINE__ );
461 hr = WsWriteStartElement( writer, NULL, &localname2, &ns2, NULL );
462 ok( hr == S_OK, "got %08x\n", hr );
463 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
465 hr = WsWriteEndElement( writer, NULL );
466 ok( hr == S_OK, "got %08x\n", hr );
467 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/>", __LINE__ );
469 hr = WsWriteEndElement( writer, NULL );
470 ok( hr == S_OK, "got %08x\n", hr );
471 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/></p:a>", __LINE__ );
473 hr = set_output( writer );
474 ok( hr == S_OK, "got %08x\n", hr );
476 hr = WsWriteStartElement( writer, &empty, &localname, &empty, NULL );
477 ok( hr == S_OK, "got %08x\n", hr );
478 hr = WsWriteEndStartElement( writer, NULL );
479 ok( hr == S_OK, "got %08x\n", hr );
480 hr = WsWriteEndElement( writer, NULL );
481 ok( hr == S_OK, "got %08x\n", hr );
482 check_output( writer, "<a></a>", __LINE__ );
484 WsFreeWriter( writer );
487 static void test_WsWriteStartAttribute(void)
489 HRESULT hr;
490 WS_XML_WRITER *writer;
491 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {3, (BYTE *)"str"};
492 WS_XML_STRING localname2 = {3, (BYTE *)"len"}, ns = {2, (BYTE *)"ns"}, empty = {0, NULL};
493 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
495 hr = WsCreateWriter( NULL, 0, &writer, NULL );
496 ok( hr == S_OK, "got %08x\n", hr );
498 hr = set_output( writer );
499 ok( hr == S_OK, "got %08x\n", hr );
501 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
502 ok( hr == S_OK, "got %08x\n", hr );
504 hr = WsWriteStartAttribute( NULL, &prefix, &localname, &ns, FALSE, NULL );
505 ok( hr == E_INVALIDARG, "got %08x\n", hr );
507 /* WsWriteStartAttribute doesn't output anything */
508 hr = WsWriteStartAttribute( writer, &prefix, &localname2, &ns, FALSE, NULL );
509 ok( hr == S_OK, "got %08x\n", hr );
510 check_output( writer, "", __LINE__ );
512 text.value.length = 1;
513 text.value.bytes = (BYTE *)"0";
514 hr = WsWriteText( writer, &text.text, NULL );
515 ok( hr == S_OK, "got %08x\n", hr );
516 check_output( writer, "", __LINE__ );
518 /* WsWriteEndAttribute doesn't output anything */
519 hr = WsWriteEndAttribute( writer, NULL );
520 ok( hr == S_OK, "got %08x\n", hr );
521 check_output( writer, "", __LINE__ );
523 hr = WsWriteEndElement( writer, NULL );
524 ok( hr == S_OK, "got %08x\n", hr );
525 check_output( writer, "<p:str p:len=\"0\" xmlns:p=\"ns\"/>", __LINE__ );
527 hr = set_output( writer );
528 ok( hr == S_OK, "got %08x\n", hr );
530 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
531 ok( hr == S_OK, "got %08x\n", hr );
533 hr = WsWriteStartAttribute( writer, &empty, &localname2, &empty, FALSE, NULL );
534 ok( hr == S_OK, "got %08x\n", hr );
535 hr = WsWriteEndAttribute( writer, NULL );
536 ok( hr == S_OK, "got %08x\n", hr );
538 hr = WsWriteEndElement( writer, NULL );
539 ok( hr == S_OK, "got %08x\n", hr );
540 check_output( writer, "<p:str len=\"\" xmlns:p=\"ns\"/>", __LINE__ );
542 hr = set_output( writer );
543 ok( hr == S_OK, "got %08x\n", hr );
545 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
546 ok( hr == S_OK, "got %08x\n", hr );
548 hr = WsWriteStartAttribute( writer, NULL, &localname2, &empty, FALSE, NULL );
549 ok( hr == S_OK, "got %08x\n", hr );
551 hr = WsWriteEndAttribute( writer, NULL );
552 ok( hr == S_OK, "got %08x\n", hr );
554 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
555 ok( hr == S_OK, "got %08x\n", hr );
557 hr = WsWriteEndAttribute( writer, NULL );
558 ok( hr == S_OK, "got %08x\n", hr );
560 hr = WsWriteEndElement( writer, NULL );
561 ok( hr == S_OK, "got %08x\n", hr );
562 check_output( writer, "<p:str len=\"\" p:str=\"\" xmlns:p=\"ns\"/>", __LINE__ );
564 WsFreeWriter( writer );
567 static void test_WsWriteType(void)
569 static const WCHAR testW[] = {'t','e','s','t',0};
570 HRESULT hr;
571 WS_XML_WRITER *writer;
572 WS_XML_STRING prefix = {1, (BYTE*)"p"}, localname = {3, (BYTE *)"str"}, ns = {2, (BYTE *)"ns"};
573 const WCHAR *val_str;
575 hr = WsCreateWriter( NULL, 0, &writer, NULL );
576 ok( hr == S_OK, "got %08x\n", hr );
578 hr = set_output( writer );
579 ok( hr == S_OK, "got %08x\n", hr );
581 val_str = testW;
582 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
583 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
584 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
586 hr = set_output( writer );
587 ok( hr == S_OK, "got %08x\n", hr );
589 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
590 ok( hr == S_OK, "got %08x\n", hr );
592 /* required value */
593 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
594 WS_WRITE_REQUIRED_VALUE, NULL, sizeof(testW), NULL );
595 ok( hr == E_INVALIDARG, "got %08x\n", hr );
597 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
598 WS_WRITE_REQUIRED_VALUE, testW, sizeof(testW), NULL );
599 ok( hr == E_INVALIDARG, "got %08x\n", hr );
601 /* required pointer */
602 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
603 WS_WRITE_REQUIRED_POINTER, NULL, sizeof(val_str), NULL );
604 ok( hr == E_INVALIDARG, "got %08x\n", hr );
606 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
607 WS_WRITE_REQUIRED_VALUE, testW, sizeof(testW), NULL );
608 ok( hr == E_INVALIDARG, "got %08x\n", hr );
610 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
611 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(WCHAR **), NULL );
612 ok( hr == S_OK, "got %08x\n", hr );
613 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
615 hr = WsWriteEndElement( writer, NULL );
616 ok( hr == S_OK, "got %08x\n", hr );
617 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
619 hr = set_output( writer );
620 ok( hr == S_OK, "got %08x\n", hr );
622 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
623 ok( hr == S_OK, "got %08x\n", hr );
625 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
626 ok( hr == S_OK, "got %08x\n", hr );
628 val_str = testW;
629 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
630 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
631 ok( hr == S_OK, "got %08x\n", hr );
632 check_output( writer, "", __LINE__ );
634 hr = WsWriteEndAttribute( writer, NULL );
635 ok( hr == S_OK, "got %08x\n", hr );
636 check_output( writer, "", __LINE__ );
638 hr = WsWriteEndElement( writer, NULL );
639 ok( hr == S_OK, "got %08x\n", hr );
640 check_output( writer, "<p:str p:str=\"test\" xmlns:p=\"ns\"/>", __LINE__ );
642 hr = set_output( writer );
643 ok( hr == S_OK, "got %08x\n", hr );
645 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
646 ok( hr == S_OK, "got %08x\n", hr );
648 val_str = testW;
649 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
650 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
651 ok( hr == S_OK, "got %08x\n", hr );
652 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
654 hr = WsWriteEndElement( writer, NULL );
655 ok( hr == S_OK, "got %08x\n", hr );
656 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
658 WsFreeWriter( writer );
661 static void prepare_basic_type_test( WS_XML_WRITER *writer )
663 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
664 HRESULT hr;
666 hr = set_output( writer );
667 ok( hr == S_OK, "got %08x\n", hr );
668 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
669 ok( hr == S_OK, "got %08x\n", hr );
672 static void test_basic_type(void)
674 static WCHAR testW[] = {'t','e','s','t',0};
675 HRESULT hr;
676 WS_XML_WRITER *writer;
677 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, xmlstr;
678 GUID guid;
679 WCHAR *str;
680 WS_STRING string;
681 WS_BYTES bytes;
682 WS_UNIQUE_ID id;
683 ULONG i;
684 static const struct
686 WS_TYPE type;
687 INT64 val;
688 ULONG size;
689 const char *result;
690 const char *result2;
692 tests[] =
694 { WS_BOOL_TYPE, TRUE, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
695 { WS_BOOL_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
696 { WS_INT8_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
697 { WS_INT16_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
698 { WS_INT32_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
699 "<t t=\"-2147483648\"/>" },
700 { WS_INT64_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
701 "<t t=\"-9223372036854775808\"/>" },
702 { WS_UINT8_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
703 { WS_UINT16_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
704 { WS_UINT32_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
705 { WS_UINT64_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
706 "<t t=\"18446744073709551615\"/>" },
709 hr = WsCreateWriter( NULL, 0, &writer, NULL );
710 ok( hr == S_OK, "got %08x\n", hr );
712 /* element content type mapping */
713 for (i = 0; i < ARRAY_SIZE( tests ); i++)
715 prepare_basic_type_test( writer );
716 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, tests[i].type, NULL,
717 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
718 ok( hr == S_OK, "%u: got %08x\n", i, hr );
720 hr = WsWriteEndElement( writer, NULL );
721 ok( hr == S_OK, "got %08x\n", hr );
722 check_output( writer, tests[i].result, __LINE__ );
725 /* element type mapping is the same as element content type mapping for basic types */
726 for (i = 0; i < ARRAY_SIZE( tests ); i++)
728 const INT64 *ptr = &tests[i].val;
730 prepare_basic_type_test( writer );
731 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL,
732 WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
733 ok( hr == S_OK, "%u: got %08x\n", i, hr );
735 hr = WsWriteEndElement( writer, NULL );
736 ok( hr == S_OK, "got %08x\n", hr );
737 check_output( writer, tests[i].result, __LINE__ );
740 /* attribute type mapping */
741 for (i = 0; i < ARRAY_SIZE( tests ); i++)
743 prepare_basic_type_test( writer );
744 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
745 ok( hr == S_OK, "got %08x\n", hr );
747 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, tests[i].type, NULL,
748 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
749 ok( hr == S_OK, "%u: got %08x\n", i, hr );
751 hr = WsWriteEndAttribute( writer, NULL );
752 ok( hr == S_OK, "got %08x\n", hr );
754 hr = WsWriteEndElement( writer, NULL );
755 ok( hr == S_OK, "got %08x\n", hr );
756 check_output( writer, tests[i].result2, __LINE__ );
759 prepare_basic_type_test( writer );
760 memset( &guid, 0, sizeof(guid) );
761 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_GUID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
762 &guid, sizeof(guid), NULL );
763 ok( hr == S_OK, "got %08x\n", hr );
764 hr = WsWriteEndElement( writer, NULL );
765 ok( hr == S_OK, "got %08x\n", hr );
766 check_output( writer, "<t>00000000-0000-0000-0000-000000000000</t>", __LINE__ );
768 prepare_basic_type_test( writer );
769 string.chars = testW;
770 string.length = 4;
771 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
772 &string, sizeof(string), NULL );
773 ok( hr == S_OK, "got %08x\n", hr );
774 hr = WsWriteEndElement( writer, NULL );
775 ok( hr == S_OK, "got %08x\n", hr );
776 check_output( writer, "<t>test</t>", __LINE__ );
778 prepare_basic_type_test( writer );
779 str = testW;
780 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL, WS_WRITE_REQUIRED_POINTER,
781 &str, sizeof(str), NULL );
782 ok( hr == S_OK, "got %08x\n", hr );
783 hr = WsWriteEndElement( writer, NULL );
784 ok( hr == S_OK, "got %08x\n", hr );
785 check_output( writer, "<t>test</t>", __LINE__ );
787 prepare_basic_type_test( writer );
788 xmlstr.bytes = (BYTE *)"test";
789 xmlstr.length = 4;
790 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
791 &xmlstr, sizeof(xmlstr), NULL );
792 ok( hr == S_OK, "got %08x\n", hr );
793 hr = WsWriteEndElement( writer, NULL );
794 ok( hr == S_OK, "got %08x\n", hr );
795 check_output( writer, "<t>test</t>", __LINE__ );
797 prepare_basic_type_test( writer );
798 bytes.bytes = (BYTE *)"test";
799 bytes.length = 4;
800 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
801 &bytes, sizeof(bytes), NULL );
802 ok( hr == S_OK, "got %08x\n", hr );
803 hr = WsWriteEndElement( writer, NULL );
804 ok( hr == S_OK, "got %08x\n", hr );
805 check_output( writer, "<t>dGVzdA==</t>", __LINE__ );
807 prepare_basic_type_test( writer );
808 bytes.length = 0;
809 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
810 &bytes, sizeof(bytes), NULL );
811 ok( hr == S_OK, "got %08x\n", hr );
812 hr = WsWriteEndElement( writer, NULL );
813 ok( hr == S_OK, "got %08x\n", hr );
814 check_output( writer, "<t/>", __LINE__ );
816 prepare_basic_type_test( writer );
817 bytes.bytes = NULL;
818 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
819 &bytes, sizeof(bytes), NULL );
820 ok( hr == S_OK, "got %08x\n", hr );
821 hr = WsWriteEndElement( writer, NULL );
822 ok( hr == S_OK, "got %08x\n", hr );
823 check_output( writer, "<t/>", __LINE__ );
825 prepare_basic_type_test( writer );
826 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_NILLABLE_VALUE,
827 &bytes, sizeof(bytes), NULL );
828 ok( hr == S_OK, "got %08x\n", hr );
829 hr = WsWriteEndElement( writer, NULL );
830 ok( hr == S_OK, "got %08x\n", hr );
831 check_output( writer, "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>",
832 __LINE__ );
834 prepare_basic_type_test( writer );
835 memset( &id, 0, sizeof(id) );
836 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_UNIQUE_ID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
837 &id, sizeof(id), NULL );
838 ok( hr == S_OK, "got %08x\n", hr );
839 hr = WsWriteEndElement( writer, NULL );
840 ok( hr == S_OK, "got %08x\n", hr );
841 check_output( writer, "<t>urn:uuid:00000000-0000-0000-0000-000000000000</t>", __LINE__ );
843 prepare_basic_type_test( writer );
844 id.uri.length = 4;
845 id.uri.chars = testW;
846 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_UNIQUE_ID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
847 &id, sizeof(id), NULL );
848 ok( hr == S_OK, "got %08x\n", hr );
849 hr = WsWriteEndElement( writer, NULL );
850 ok( hr == S_OK, "got %08x\n", hr );
851 check_output( writer, "<t>test</t>", __LINE__ );
853 WsFreeWriter( writer );
856 static void test_simple_struct_type(void)
858 static const WCHAR valueW[] = {'v','a','l','u','e',0};
859 HRESULT hr;
860 WS_XML_WRITER *writer;
861 WS_STRUCT_DESCRIPTION s;
862 WS_FIELD_DESCRIPTION f, *fields[1];
863 WS_XML_STRING localname = {6, (BYTE *)"struct"}, ns = {0, NULL};
864 struct test
866 const WCHAR *field;
867 } *test;
869 hr = WsCreateWriter( NULL, 0, &writer, NULL );
870 ok( hr == S_OK, "got %08x\n", hr );
872 hr = set_output( writer );
873 ok( hr == S_OK, "got %08x\n", hr );
875 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
876 ok( hr == S_OK, "got %08x\n", hr );
878 memset( &f, 0, sizeof(f) );
879 f.mapping = WS_TEXT_FIELD_MAPPING;
880 f.type = WS_WSZ_TYPE;
881 fields[0] = &f;
883 memset( &s, 0, sizeof(s) );
884 s.size = sizeof(struct test);
885 s.alignment = TYPE_ALIGNMENT(struct test);
886 s.fields = fields;
887 s.fieldCount = 1;
889 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
890 test->field = valueW;
891 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
892 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
893 ok( hr == E_INVALIDARG, "got %08x\n", hr );
895 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
896 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
897 ok( hr == E_INVALIDARG, "got %08x\n", hr );
899 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
900 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
901 ok( hr == S_OK, "got %08x\n", hr );
903 hr = WsWriteEndElement( writer, NULL );
904 ok( hr == S_OK, "got %08x\n", hr );
905 check_output( writer, "<struct>value</struct>", __LINE__ );
907 /* required value */
908 hr = set_output( writer );
909 ok( hr == S_OK, "got %08x\n", hr );
911 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
912 ok( hr == S_OK, "got %08x\n", hr );
914 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
915 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
916 ok( hr == S_OK, "got %08x\n", hr );
918 hr = WsWriteEndElement( writer, NULL );
919 ok( hr == S_OK, "got %08x\n", hr );
920 check_output( writer, "<struct>value</struct>", __LINE__ );
922 hr = set_output( writer );
923 ok( hr == S_OK, "got %08x\n", hr );
925 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
926 ok( hr == S_OK, "got %08x\n", hr );
928 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
929 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
930 ok( hr == S_OK, "got %08x\n", hr );
932 hr = WsWriteEndElement( writer, NULL );
933 ok( hr == S_OK, "got %08x\n", hr );
934 check_output( writer, "<struct>value</struct>", __LINE__ );
936 hr = set_output( writer );
937 ok( hr == S_OK, "got %08x\n", hr );
939 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
940 ok( hr == S_OK, "got %08x\n", hr );
942 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
943 ok( hr == S_OK, "got %08x\n", hr );
945 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
946 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
947 ok( hr == S_OK, "got %08x\n", hr );
949 hr = WsWriteEndAttribute( writer, NULL );
950 ok( hr == S_OK, "got %08x\n", hr );
952 hr = WsWriteEndElement( writer, NULL );
953 ok( hr == S_OK, "got %08x\n", hr );
954 check_output( writer, "<struct struct=\"value\"/>", __LINE__ );
956 HeapFree( GetProcessHeap(), 0, test );
957 WsFreeWriter( writer );
960 static void test_WsWriteElement(void)
962 static const WCHAR testW[] = {'t','e','s','t',0};
963 HRESULT hr;
964 WS_XML_WRITER *writer;
965 WS_STRUCT_DESCRIPTION s;
966 WS_FIELD_DESCRIPTION f, *fields[1];
967 WS_ELEMENT_DESCRIPTION desc;
968 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
969 struct test { const WCHAR *str; } *test;
971 hr = WsCreateWriter( NULL, 0, &writer, NULL );
972 ok( hr == S_OK, "got %08x\n", hr );
974 hr = set_output( writer );
975 ok( hr == S_OK, "got %08x\n", hr );
977 /* text field mapping */
978 memset( &f, 0, sizeof(f) );
979 f.mapping = WS_TEXT_FIELD_MAPPING;
980 f.type = WS_WSZ_TYPE;
981 fields[0] = &f;
983 memset( &s, 0, sizeof(s) );
984 s.size = sizeof(struct test);
985 s.alignment = TYPE_ALIGNMENT(struct test);
986 s.fields = fields;
987 s.fieldCount = 1;
989 desc.elementLocalName = &localname;
990 desc.elementNs = &ns;
991 desc.type = WS_STRUCT_TYPE;
992 desc.typeDescription = &s;
994 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
995 test->str = testW;
996 hr = WsWriteElement( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
997 ok( hr == E_INVALIDARG, "got %08x\n", hr );
999 hr = WsWriteElement( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1000 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1002 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
1003 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1005 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1006 ok( hr == S_OK, "got %08x\n", hr );
1007 check_output( writer, "<str>test</str>", __LINE__ );
1009 hr = set_output( writer );
1010 ok( hr == S_OK, "got %08x\n", hr );
1012 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1013 ok( hr == S_OK, "got %08x\n", hr );
1015 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1016 ok( hr == S_OK, "got %08x\n", hr );
1017 check_output( writer, "<str><str>test</str>", __LINE__ );
1019 hr = set_output( writer );
1020 ok( hr == S_OK, "got %08x\n", hr );
1022 /* attribute field mapping */
1023 f.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
1025 /* requires localName and ns to be set */
1026 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1027 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1029 hr = set_output( writer );
1030 ok( hr == S_OK, "got %08x\n", hr );
1032 f.localName = &localname;
1033 f.ns = &ns;
1034 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1035 ok( hr == S_OK, "got %08x\n", hr );
1036 check_output( writer, "<str str=\"test\"/>", __LINE__ );
1038 HeapFree( GetProcessHeap(), 0, test );
1039 WsFreeWriter( writer );
1042 static void test_WsWriteValue(void)
1044 HRESULT hr;
1045 WS_XML_WRITER *writer;
1046 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1047 ULONG i;
1048 static const struct
1050 WS_VALUE_TYPE type;
1051 INT64 val;
1052 ULONG size;
1053 const char *result;
1054 const char *result2;
1056 tests[] =
1058 { WS_BOOL_VALUE_TYPE, ~0, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
1059 { WS_BOOL_VALUE_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
1060 { WS_INT8_VALUE_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
1061 { WS_INT16_VALUE_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
1062 { WS_INT32_VALUE_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
1063 "<t t=\"-2147483648\"/>" },
1064 { WS_INT64_VALUE_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
1065 "<t t=\"-9223372036854775808\"/>" },
1066 { WS_UINT8_VALUE_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
1067 { WS_UINT16_VALUE_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
1068 { WS_UINT32_VALUE_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
1069 { WS_UINT64_VALUE_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
1070 "<t t=\"18446744073709551615\"/>" },
1073 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1074 ok( hr == S_OK, "got %08x\n", hr );
1076 hr = set_output( writer );
1077 ok( hr == S_OK, "got %08x\n", hr );
1079 hr = WsWriteValue( NULL, tests[0].type, &tests[0].val, tests[0].size, NULL );
1080 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1082 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, tests[0].size, NULL );
1083 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1085 hr = set_output( writer );
1086 ok( hr == S_OK, "got %08x\n", hr );
1088 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1089 ok( hr == S_OK, "got %08x\n", hr );
1091 /* zero size */
1092 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, 0, NULL );
1093 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1095 hr = set_output( writer );
1096 ok( hr == S_OK, "got %08x\n", hr );
1098 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1099 ok( hr == S_OK, "got %08x\n", hr );
1101 /* NULL value */
1102 hr = WsWriteValue( writer, tests[0].type, NULL, 0, NULL );
1103 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1105 /* element type mapping */
1106 for (i = 0; i < ARRAY_SIZE( tests ); i++)
1108 hr = set_output( writer );
1109 ok( hr == S_OK, "got %08x\n", hr );
1111 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1112 ok( hr == S_OK, "got %08x\n", hr );
1114 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1115 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1117 hr = WsWriteEndElement( writer, NULL );
1118 ok( hr == S_OK, "got %08x\n", hr );
1119 check_output( writer, tests[i].result, __LINE__ );
1122 /* attribute type mapping */
1123 for (i = 0; i < ARRAY_SIZE( tests ); i++)
1125 hr = set_output( writer );
1126 ok( hr == S_OK, "got %08x\n", hr );
1128 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1129 ok( hr == S_OK, "got %08x\n", hr );
1131 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
1132 ok( hr == S_OK, "got %08x\n", hr );
1134 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1135 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1137 hr = WsWriteEndAttribute( writer, NULL );
1138 ok( hr == S_OK, "got %08x\n", hr );
1140 hr = WsWriteEndElement( writer, NULL );
1141 ok( hr == S_OK, "got %08x\n", hr );
1142 check_output( writer, tests[i].result2, __LINE__ );
1145 WsFreeWriter( writer );
1148 static void test_WsWriteAttribute(void)
1150 static const WCHAR testW[] = {'t','e','s','t',0};
1151 HRESULT hr;
1152 WS_XML_WRITER *writer;
1153 WS_STRUCT_DESCRIPTION s;
1154 WS_FIELD_DESCRIPTION f, *fields[1];
1155 WS_ATTRIBUTE_DESCRIPTION desc;
1156 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
1157 struct test { const WCHAR *str; } *test;
1159 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1160 ok( hr == S_OK, "got %08x\n", hr );
1162 hr = set_output( writer );
1163 ok( hr == S_OK, "got %08x\n", hr );
1165 /* text field mapping */
1166 memset( &f, 0, sizeof(f) );
1167 f.mapping = WS_TEXT_FIELD_MAPPING;
1168 f.type = WS_WSZ_TYPE;
1169 fields[0] = &f;
1171 memset( &s, 0, sizeof(s) );
1172 s.size = sizeof(struct test);
1173 s.alignment = TYPE_ALIGNMENT(struct test);
1174 s.fields = fields;
1175 s.fieldCount = 1;
1177 desc.attributeLocalName = &localname;
1178 desc.attributeNs = &ns;
1179 desc.type = WS_STRUCT_TYPE;
1180 desc.typeDescription = &s;
1182 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
1183 test->str = testW;
1184 hr = WsWriteAttribute( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1185 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1187 hr = WsWriteAttribute( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1188 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1190 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
1191 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1193 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1194 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1196 hr = set_output( writer );
1197 ok( hr == S_OK, "got %08x\n", hr );
1199 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1200 ok( hr == S_OK, "got %08x\n", hr );
1202 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1203 ok( hr == S_OK, "got %08x\n", hr );
1205 hr = WsWriteEndElement( writer, NULL );
1206 ok( hr == S_OK, "got %08x\n", hr );
1207 check_output( writer, "<str str=\"test\"/>", __LINE__ );
1209 HeapFree( GetProcessHeap(), 0, test );
1210 WsFreeWriter( writer );
1213 static void test_WsWriteStartCData(void)
1215 HRESULT hr;
1216 WS_XML_WRITER *writer;
1217 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1218 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
1220 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1221 ok( hr == S_OK, "got %08x\n", hr );
1223 hr = set_output( writer );
1224 ok( hr == S_OK, "got %08x\n", hr );
1226 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1227 ok( hr == S_OK, "got %08x\n", hr );
1229 hr = WsWriteEndCData( writer, NULL );
1230 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1232 hr = set_output( writer );
1233 ok( hr == S_OK, "got %08x\n", hr );
1235 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1236 ok( hr == S_OK, "got %08x\n", hr );
1237 check_output( writer, "", __LINE__ );
1239 hr = WsWriteStartCData( writer, NULL );
1240 ok( hr == S_OK, "got %08x\n", hr );
1241 check_output( writer, "<t><![CDATA[", __LINE__ );
1243 text.value.bytes = (BYTE *)"<data>";
1244 text.value.length = 6;
1245 hr = WsWriteText( writer, &text.text, NULL );
1246 ok( hr == S_OK, "got %08x\n", hr );
1247 check_output( writer, "<t><![CDATA[<data>", __LINE__ );
1249 hr = WsWriteEndCData( writer, NULL );
1250 ok( hr == S_OK, "got %08x\n", hr );
1251 check_output( writer, "<t><![CDATA[<data>]]>", __LINE__ );
1253 hr = WsWriteEndElement( writer, NULL );
1254 ok( hr == S_OK, "got %08x\n", hr );
1255 check_output( writer, "<t><![CDATA[<data>]]></t>", __LINE__ );
1257 WsFreeWriter( writer );
1260 static void check_output_buffer( WS_XML_BUFFER *buffer, const char *expected, unsigned int line )
1262 WS_XML_WRITER *writer;
1263 WS_BYTES bytes;
1264 ULONG size = sizeof(bytes);
1265 int len = strlen(expected);
1266 HRESULT hr;
1268 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1269 ok( hr == S_OK, "got %08x\n", hr );
1271 hr = set_output( writer );
1272 ok( hr == S_OK, "got %08x\n", hr );
1274 hr = WsWriteXmlBuffer( writer, buffer, NULL );
1275 ok( hr == S_OK, "got %08x\n", hr );
1277 memset( &bytes, 0, sizeof(bytes) );
1278 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
1279 ok( hr == S_OK, "%u: got %08x\n", line, hr );
1280 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
1281 if (bytes.length != len) return;
1282 ok( !memcmp( bytes.bytes, expected, len ), "%u: got %s expected %s\n", line, bytes.bytes, expected );
1284 WsFreeWriter( writer );
1287 static void prepare_xmlns_test( WS_XML_WRITER *writer, WS_HEAP **heap, WS_XML_BUFFER **buffer )
1289 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1290 HRESULT hr;
1292 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, heap, NULL );
1293 ok( hr == S_OK, "got %08x\n", hr );
1295 hr = WsCreateXmlBuffer( *heap, NULL, 0, buffer, NULL );
1296 ok( hr == S_OK, "got %08x\n", hr );
1298 hr = WsSetOutputToBuffer( writer, *buffer, NULL, 0, NULL );
1299 ok( hr == S_OK, "got %08x\n", hr );
1301 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
1302 ok( hr == S_OK, "got %08x\n", hr );
1305 static void test_WsWriteXmlnsAttribute(void)
1307 WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1308 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, prefix2 = {7, (BYTE *)"prefix2"};
1309 WS_XML_STRING xmlns = {6, (BYTE *)"xmlns"}, attr = {4, (BYTE *)"attr"};
1310 WS_XML_STRING localname = {1, (BYTE *)"u"};
1311 WS_HEAP *heap;
1312 WS_XML_BUFFER *buffer;
1313 WS_XML_WRITER *writer;
1314 HRESULT hr;
1316 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1317 ok( hr == S_OK, "got %08x\n", hr );
1319 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1320 ok( hr == S_OK, "got %08x\n", hr );
1322 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1323 ok( hr == S_OK, "got %08x\n", hr );
1325 hr = WsWriteXmlnsAttribute( NULL, NULL, NULL, FALSE, NULL );
1326 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1327 WsFreeHeap( heap );
1329 prepare_xmlns_test( writer, &heap, &buffer );
1330 hr = WsWriteXmlnsAttribute( writer, NULL, NULL, FALSE, NULL );
1331 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1332 WsFreeHeap( heap );
1334 prepare_xmlns_test( writer, &heap, &buffer );
1335 hr = WsWriteXmlnsAttribute( writer, &prefix2, NULL, FALSE, NULL );
1336 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1338 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1339 ok( hr == S_OK, "got %08x\n", hr );
1340 hr = WsWriteXmlnsAttribute( writer, NULL, &ns, FALSE, NULL );
1341 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1342 WsFreeHeap( heap );
1344 /* no prefix */
1345 prepare_xmlns_test( writer, &heap, &buffer );
1346 hr = WsWriteXmlnsAttribute( writer, NULL, &ns2, FALSE, NULL );
1347 ok( hr == S_OK, "got %08x\n", hr );
1348 hr = WsWriteEndElement( writer, NULL );
1349 ok( hr == S_OK, "got %08x\n", hr );
1350 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\" xmlns=\"ns2\"/>", __LINE__ );
1351 WsFreeHeap( heap );
1353 /* prefix */
1354 prepare_xmlns_test( writer, &heap, &buffer );
1355 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1356 ok( hr == S_OK, "got %08x\n", hr );
1357 hr = WsWriteEndElement( writer, NULL );
1358 ok( hr == S_OK, "got %08x\n", hr );
1359 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns2\" xmlns:prefix=\"ns\"/>", __LINE__ );
1360 WsFreeHeap( heap );
1362 /* implicitly set element prefix namespace */
1363 prepare_xmlns_test( writer, &heap, &buffer );
1364 hr = WsWriteEndElement( writer, NULL );
1365 ok( hr == S_OK, "got %08x\n", hr );
1366 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\"/>", __LINE__ );
1367 WsFreeHeap( heap );
1369 /* explicitly set element prefix namespace */
1370 prepare_xmlns_test( writer, &heap, &buffer );
1371 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1372 ok( hr == S_OK, "got %08x\n", hr );
1373 hr = WsWriteEndElement( writer, NULL );
1374 ok( hr == S_OK, "got %08x\n", hr );
1375 check_output_buffer( buffer, "<prefix:t xmlns:prefix='ns'/>", __LINE__ );
1376 WsFreeHeap( heap );
1378 /* repeated calls, same namespace */
1379 prepare_xmlns_test( writer, &heap, &buffer );
1380 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1381 ok( hr == S_OK, "got %08x\n", hr );
1382 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1383 ok( hr == S_OK, "got %08x\n", hr );
1384 hr = WsWriteEndElement( writer, NULL );
1385 ok( hr == S_OK, "got %08x\n", hr );
1386 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns\" xmlns:prefix=\"ns\"/>", __LINE__ );
1387 WsFreeHeap( heap );
1389 /* repeated calls, different namespace */
1390 prepare_xmlns_test( writer, &heap, &buffer );
1391 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1392 ok( hr == S_OK, "got %08x\n", hr );
1393 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1394 ok( hr == S_OK, "got %08x\n", hr );
1395 hr = WsWriteEndElement( writer, NULL );
1396 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1397 WsFreeHeap( heap );
1399 /* single quotes */
1400 prepare_xmlns_test( writer, &heap, &buffer );
1401 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, TRUE, NULL );
1402 ok( hr == S_OK, "got %08x\n", hr );
1403 hr = WsWriteEndElement( writer, NULL );
1404 ok( hr == S_OK, "got %08x\n", hr );
1405 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns' xmlns:prefix=\"ns\"/>", __LINE__ );
1406 WsFreeHeap( heap );
1408 /* different namespace, different prefix */
1409 prepare_xmlns_test( writer, &heap, &buffer );
1410 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1411 ok( hr == S_OK, "got %08x\n", hr );
1412 hr = WsWriteEndElement( writer, NULL );
1413 ok( hr == S_OK, "got %08x\n", hr );
1414 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"/>", __LINE__ );
1415 WsFreeHeap( heap );
1417 /* different namespace, same prefix */
1418 prepare_xmlns_test( writer, &heap, &buffer );
1419 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns2, TRUE, NULL );
1420 ok( hr == S_OK, "got %08x\n", hr );
1421 hr = WsWriteEndElement( writer, NULL );
1422 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1423 WsFreeHeap( heap );
1425 /* regular attribute */
1426 prepare_xmlns_test( writer, &heap, &buffer );
1427 hr = WsWriteStartAttribute( writer, &xmlns, &prefix2, &ns2, TRUE, NULL );
1428 ok( hr == S_OK, "got %08x\n", hr );
1429 hr = WsWriteEndAttribute( writer, NULL );
1430 ok( hr == S_OK, "got %08x\n", hr );
1431 hr = WsWriteEndElement( writer, NULL );
1432 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1433 WsFreeHeap( heap );
1435 /* attribute order */
1436 prepare_xmlns_test( writer, &heap, &buffer );
1437 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1438 ok( hr == S_OK, "got %08x\n", hr );
1439 hr = WsWriteStartAttribute( writer, &prefix, &attr, &ns, TRUE, NULL );
1440 ok( hr == S_OK, "got %08x\n", hr );
1441 hr = WsWriteEndAttribute( writer, NULL );
1442 ok( hr == S_OK, "got %08x\n", hr );
1443 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1444 ok( hr == S_OK, "got %08x\n", hr );
1445 hr = WsWriteEndElement( writer, NULL );
1446 ok( hr == S_OK, "got %08x\n", hr );
1447 check_output_buffer( buffer, "<prefix:t prefix:attr='' xmlns:prefix='ns' xmlns:prefix2='ns2'/>", __LINE__ );
1448 WsFreeHeap( heap );
1450 /* scope */
1451 prepare_xmlns_test( writer, &heap, &buffer );
1452 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1453 ok( hr == S_OK, "got %08x\n", hr );
1454 hr = WsWriteStartElement( writer, &prefix2, &localname, &ns2, NULL );
1455 ok( hr == S_OK, "got %08x\n", hr );
1456 hr = WsWriteEndElement( writer, NULL );
1457 ok( hr == S_OK, "got %08x\n", hr );
1458 hr = WsWriteEndElement( writer, NULL );
1459 ok( hr == S_OK, "got %08x\n", hr );
1460 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"><prefix2:u/></prefix:t>",
1461 __LINE__ );
1462 WsFreeHeap( heap );
1464 WsFreeWriter( writer );
1467 static void prepare_prefix_test( WS_XML_WRITER *writer )
1469 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1470 HRESULT hr;
1472 hr = set_output( writer );
1473 ok( hr == S_OK, "got %08x\n", hr );
1474 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1475 ok( hr == S_OK, "got %08x\n", hr );
1476 hr = WsWriteEndStartElement( writer, NULL );
1477 ok( hr == S_OK, "got %08x\n", hr );
1480 static void test_WsGetPrefixFromNamespace(void)
1482 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, *prefix;
1483 const WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1484 WS_XML_WRITER *writer;
1485 HRESULT hr;
1487 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1488 ok( hr == S_OK, "got %08x\n", hr );
1490 hr = set_output( writer );
1491 ok( hr == S_OK, "got %08x\n", hr );
1492 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1493 ok( hr == S_OK, "got %08x\n", hr );
1495 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, NULL, NULL );
1496 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1498 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, &prefix, NULL );
1499 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1501 hr = WsGetPrefixFromNamespace( writer, NULL, FALSE, &prefix, NULL );
1502 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1504 /* element must be committed */
1505 hr = set_output( writer );
1506 ok( hr == S_OK, "got %08x\n", hr );
1507 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1508 ok( hr == S_OK, "got %08x\n", hr );
1509 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1510 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1512 /* but writer can't be positioned on end element node */
1513 hr = set_output( writer );
1514 ok( hr == S_OK, "got %08x\n", hr );
1515 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1516 ok( hr == S_OK, "got %08x\n", hr );
1517 hr = WsWriteEndElement( writer, NULL );
1518 ok( hr == S_OK, "got %08x\n", hr );
1519 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1520 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1522 /* required = TRUE */
1523 prefix = NULL;
1524 prepare_prefix_test( writer );
1525 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1526 ok( hr == S_OK, "got %08x\n", hr );
1527 ok( prefix != NULL, "prefix not set\n" );
1528 if (prefix)
1530 ok( prefix->length == 1, "got %u\n", prefix->length );
1531 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1534 prefix = (const WS_XML_STRING *)0xdeadbeef;
1535 hr = WsGetPrefixFromNamespace( writer, &ns2, TRUE, &prefix, NULL );
1536 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1537 ok( prefix == (const WS_XML_STRING *)0xdeadbeef, "prefix set\n" );
1539 /* required = FALSE */
1540 prefix = NULL;
1541 prepare_prefix_test( writer );
1542 hr = WsGetPrefixFromNamespace( writer, &ns, FALSE, &prefix, NULL );
1543 ok( hr == S_OK, "got %08x\n", hr );
1544 ok( prefix != NULL, "prefix not set\n" );
1545 if (prefix)
1547 ok( prefix->length == 1, "got %u\n", prefix->length );
1548 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1551 prefix = (const WS_XML_STRING *)0xdeadbeef;
1552 hr = WsGetPrefixFromNamespace( writer, &ns2, FALSE, &prefix, NULL );
1553 ok( hr == S_FALSE, "got %08x\n", hr );
1554 ok( prefix == NULL, "prefix not set\n" );
1556 WsFreeWriter( writer );
1559 static void test_complex_struct_type(void)
1561 static const char expected[] =
1562 "<o:OfficeConfig xmlns:o=\"urn:schemas-microsoft-com:office:office\">"
1563 "<o:services o:GenerationTime=\"2015-09-03T18:47:54\"/>"
1564 "</o:OfficeConfig>";
1565 static const WCHAR timestampW[] =
1566 {'2','0','1','5','-','0','9','-','0','3','T','1','8',':','4','7',':','5','4',0};
1567 WS_XML_STRING str_officeconfig = {12, (BYTE *)"OfficeConfig"};
1568 WS_XML_STRING str_services = {8, (BYTE *)"services"};
1569 WS_XML_STRING str_generationtime = {14, (BYTE *)"GenerationTime"};
1570 WS_XML_STRING ns = {39, (BYTE *)"urn:schemas-microsoft-com:office:office"};
1571 WS_XML_STRING prefix = {1, (BYTE *)"o"};
1572 DWORD size;
1573 HRESULT hr;
1574 WS_HEAP *heap;
1575 WS_XML_BUFFER *buffer;
1576 WS_XML_WRITER *writer;
1577 WS_STRUCT_DESCRIPTION s, s2;
1578 WS_FIELD_DESCRIPTION f, f2, *fields[1], *fields2[1];
1579 struct services
1581 const WCHAR *generationtime;
1583 struct officeconfig
1585 struct services *services;
1586 } *test;
1588 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1589 ok( hr == S_OK, "got %08x\n", hr );
1591 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1592 ok( hr == S_OK, "got %08x\n", hr );
1594 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1595 ok( hr == S_OK, "got %08x\n", hr );
1597 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1598 ok( hr == S_OK, "got %08x\n", hr );
1600 hr = WsWriteStartElement( writer, &prefix, &str_officeconfig, &ns, NULL );
1601 ok( hr == S_OK, "got %08x\n", hr );
1603 memset( &f2, 0, sizeof(f2) );
1604 f2.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
1605 f2.localName = &str_generationtime;
1606 f2.ns = &ns;
1607 f2.type = WS_WSZ_TYPE;
1608 f2.options = WS_FIELD_OPTIONAL;
1609 fields2[0] = &f2;
1611 memset( &s2, 0, sizeof(s2) );
1612 s2.size = sizeof(*test->services);
1613 s2.alignment = 4;
1614 s2.fields = fields2;
1615 s2.fieldCount = 1;
1616 s2.typeLocalName = &str_services;
1617 s2.typeNs = &ns;
1619 memset( &f, 0, sizeof(f) );
1620 f.mapping = WS_ELEMENT_FIELD_MAPPING;
1621 f.localName = &str_services;
1622 f.ns = &ns;
1623 f.type = WS_STRUCT_TYPE;
1624 f.typeDescription = &s2;
1625 f.options = WS_FIELD_POINTER;
1626 fields[0] = &f;
1628 memset( &s, 0, sizeof(s) );
1629 s.size = sizeof(*test);
1630 s.alignment = 4;
1631 s.fields = fields;
1632 s.fieldCount = 1;
1633 s.typeLocalName = &str_officeconfig;
1634 s.typeNs = &ns;
1636 size = sizeof(struct officeconfig) + sizeof(struct services);
1637 test = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
1638 test->services = (struct services *)(test + 1);
1639 test->services->generationtime = timestampW;
1640 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
1641 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1642 ok( hr == S_OK, "got %08x\n", hr );
1644 hr = WsWriteEndElement( writer, NULL );
1645 ok( hr == S_OK, "got %08x\n", hr );
1646 check_output_buffer( buffer, expected, __LINE__ );
1648 HeapFree( GetProcessHeap(), 0, test );
1649 WsFreeWriter( writer );
1650 WsFreeHeap( heap );
1653 static void test_WsMoveWriter(void)
1655 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"}, ns = {0, NULL};
1656 WS_HEAP *heap;
1657 WS_XML_WRITER *writer;
1658 WS_XML_BUFFER *buffer;
1659 HRESULT hr;
1661 hr = WsMoveWriter( NULL, WS_MOVE_TO_EOF, NULL, NULL );
1662 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1664 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1665 ok( hr == S_OK, "got %08x\n", hr );
1667 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1668 ok( hr == S_OK, "got %08x\n", hr );
1670 hr = set_output( writer );
1671 ok( hr == S_OK, "got %08x\n", hr );
1673 /* writer must be set to an XML buffer */
1674 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1675 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1677 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1678 ok( hr == S_OK, "got %08x\n", hr );
1680 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1681 ok( hr == S_OK, "got %08x\n", hr );
1683 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1684 ok( hr == S_OK, "got %08x\n", hr );
1686 /* <a><b/></a> */
1687 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1688 ok( hr == S_OK, "got %08x\n", hr );
1690 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
1691 ok( hr == S_OK, "got %08x\n", hr );
1693 hr = WsWriteEndElement( writer, NULL );
1694 ok( hr == S_OK, "got %08x\n", hr );
1696 hr = WsWriteEndElement( writer, NULL );
1697 ok( hr == S_OK, "got %08x\n", hr );
1699 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1700 ok( hr == S_OK, "got %08x\n", hr );
1702 hr = WsMoveWriter( writer, WS_MOVE_TO_ROOT_ELEMENT, NULL, NULL );
1703 ok( hr == S_OK, "got %08x\n", hr );
1705 hr = WsMoveWriter( writer, WS_MOVE_TO_CHILD_ELEMENT, NULL, NULL );
1706 ok( hr == S_OK, "got %08x\n", hr );
1708 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1709 ok( hr == S_OK, "got %08x\n", hr );
1711 hr = WsMoveWriter( writer, WS_MOVE_TO_PARENT_ELEMENT, NULL, NULL );
1712 ok( hr == S_OK, "got %08x\n", hr );
1714 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1715 ok( hr == S_OK, "got %08x\n", hr );
1717 hr = WsMoveWriter( writer, WS_MOVE_TO_BOF, NULL, NULL );
1718 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1720 WsFreeWriter( writer );
1721 WsFreeHeap( heap );
1724 static void test_WsGetWriterPosition(void)
1726 WS_HEAP *heap;
1727 WS_XML_WRITER *writer;
1728 WS_XML_BUFFER *buffer;
1729 WS_XML_NODE_POSITION pos;
1730 HRESULT hr;
1732 hr = WsGetWriterPosition( NULL, NULL, NULL );
1733 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1735 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1736 ok( hr == S_OK, "got %08x\n", hr );
1738 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1739 ok( hr == S_OK, "got %08x\n", hr );
1741 hr = WsGetWriterPosition( writer, &pos, NULL );
1742 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1744 hr = set_output( writer );
1745 ok( hr == S_OK, "got %08x\n", hr );
1747 /* writer must be set to an XML buffer */
1748 hr = WsGetWriterPosition( writer, &pos, NULL );
1749 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1751 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1752 ok( hr == S_OK, "got %08x\n", hr );
1754 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1755 ok( hr == S_OK, "got %08x\n", hr );
1757 hr = WsGetWriterPosition( writer, NULL, NULL );
1758 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1760 pos.buffer = pos.node = NULL;
1761 hr = WsGetWriterPosition( writer, &pos, NULL );
1762 ok( hr == S_OK, "got %08x\n", hr );
1763 ok( pos.buffer != NULL, "buffer not set\n" );
1764 ok( pos.node != NULL, "node not set\n" );
1766 WsFreeWriter( writer );
1767 WsFreeHeap( heap );
1770 static void test_WsSetWriterPosition(void)
1772 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1773 WS_HEAP *heap;
1774 WS_XML_WRITER *writer;
1775 WS_XML_BUFFER *buf1, *buf2;
1776 WS_XML_NODE_POSITION pos;
1777 HRESULT hr;
1779 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1780 ok( hr == S_OK, "got %08x\n", hr );
1782 hr = WsSetWriterPosition( NULL, NULL, NULL );
1783 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1785 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1786 ok( hr == S_OK, "got %08x\n", hr );
1788 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf1, NULL );
1789 ok( hr == S_OK, "got %08x\n", hr );
1791 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1792 ok( hr == S_OK, "got %08x\n", hr );
1794 hr = WsSetWriterPosition( writer, NULL, NULL );
1795 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1797 pos.buffer = pos.node = NULL;
1798 hr = WsGetWriterPosition( writer, &pos, NULL );
1799 ok( hr == S_OK, "got %08x\n", hr );
1800 ok( pos.buffer == buf1, "wrong buffer\n" );
1801 ok( pos.node != NULL, "node not set\n" );
1803 hr = WsSetWriterPosition( writer, &pos, NULL );
1804 ok( hr == S_OK, "got %08x\n", hr );
1806 /* different buffer */
1807 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf2, NULL );
1808 ok( hr == S_OK, "got %08x\n", hr );
1810 pos.buffer = buf2;
1811 hr = WsSetWriterPosition( writer, &pos, NULL );
1812 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1814 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1815 ok( hr == S_OK, "got %08x\n", hr );
1817 /* try to write at non-final position */
1818 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1819 ok( hr == S_OK, "got %08x\n", hr );
1821 pos.buffer = pos.node = NULL;
1822 hr = WsGetWriterPosition( writer, &pos, NULL );
1823 ok( hr == S_OK, "got %08x\n", hr );
1824 ok( pos.buffer == buf1, "wrong buffer\n" );
1825 ok( pos.node != NULL, "node not set\n" );
1827 hr = WsWriteEndElement( writer, NULL );
1828 ok( hr == S_OK, "got %08x\n", hr );
1829 check_output_buffer( buf1, "<t/>", __LINE__ );
1831 hr = WsSetWriterPosition( writer, &pos, NULL );
1832 ok( hr == S_OK, "got %08x\n", hr );
1834 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1835 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1837 WsFreeWriter( writer );
1838 WsFreeHeap( heap );
1841 static void test_WsWriteXmlBuffer(void)
1843 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1844 WS_XML_WRITER *writer1, *writer2;
1845 WS_XML_BUFFER *buffer1, *buffer2;
1846 WS_HEAP *heap;
1847 HRESULT hr;
1849 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1850 ok( hr == S_OK, "got %08x\n", hr );
1852 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
1853 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1855 hr = WsCreateWriter( NULL, 0, &writer1, NULL );
1856 ok( hr == S_OK, "got %08x\n", hr );
1858 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
1859 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1861 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer1, NULL );
1862 ok( hr == S_OK, "got %08x\n", hr );
1864 hr = WsSetOutputToBuffer( writer1, buffer1, NULL, 0, NULL );
1865 ok( hr == S_OK, "got %08x\n", hr );
1867 hr = WsWriteStartElement( writer1, NULL, &localname, &ns, NULL );
1868 ok( hr == S_OK, "got %08x\n", hr );
1870 hr = WsWriteEndElement( writer1, NULL );
1871 ok( hr == S_OK, "got %08x\n", hr );
1872 check_output_buffer( buffer1, "<t/>", __LINE__ );
1874 hr = WsCreateWriter( NULL, 0, &writer2, NULL );
1875 ok( hr == S_OK, "got %08x\n", hr );
1877 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer2, NULL );
1878 ok( hr == S_OK, "got %08x\n", hr );
1880 hr = WsSetOutputToBuffer( writer2, buffer2, NULL, 0, NULL );
1881 ok( hr == S_OK, "got %08x\n", hr );
1883 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1884 ok( hr == S_OK, "got %08x\n", hr );
1885 check_output_buffer( buffer2, "<t/>", __LINE__ );
1887 hr = WsMoveWriter( writer2, WS_MOVE_TO_PREVIOUS_ELEMENT, NULL, NULL );
1888 todo_wine ok( hr == S_OK, "got %08x\n", hr );
1890 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1891 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1893 WsFreeWriter( writer1 );
1894 WsFreeWriter( writer2 );
1895 WsFreeHeap( heap );
1898 static void test_WsWriteNode(void)
1900 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {4, (BYTE *)"attr"}, ns = {0, NULL};
1901 WS_XML_WRITER *writer;
1902 WS_XML_BUFFER *buffer;
1903 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
1904 WS_XML_ATTRIBUTE attr, *attrs[1];
1905 WS_XML_ELEMENT_NODE elem;
1906 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
1907 WS_XML_NODE node;
1908 WS_XML_TEXT_NODE text = {{WS_XML_NODE_TYPE_TEXT}};
1909 WS_HEAP *heap;
1910 HRESULT hr;
1912 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1913 ok( hr == S_OK, "got %08x\n", hr );
1915 hr = WsWriteNode( NULL, NULL, NULL );
1916 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1918 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1919 ok( hr == S_OK, "got %08x\n", hr );
1921 hr = WsWriteNode( writer, NULL, NULL );
1922 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1924 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1925 ok( hr == S_OK, "got %08x\n", hr );
1927 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1928 ok( hr == S_OK, "got %08x\n", hr );
1930 utf8.value.bytes = (BYTE *)"value";
1931 utf8.value.length = sizeof("value") - 1;
1933 attr.singleQuote = TRUE;
1934 attr.isXmlNs = FALSE;
1935 attr.prefix = NULL;
1936 attr.localName = &localname2;
1937 attr.ns = &ns;
1938 attr.value = &utf8.text;
1939 attrs[0] = &attr;
1941 elem.node.nodeType = WS_XML_NODE_TYPE_ELEMENT;
1942 elem.prefix = NULL;
1943 elem.localName = &localname;
1944 elem.ns = &ns;
1945 elem.attributeCount = 1;
1946 elem.attributes = attrs;
1947 elem.isEmpty = FALSE;
1948 hr = WsWriteNode( writer, &elem.node, NULL );
1949 ok( hr == S_OK, "got %08x\n", hr );
1951 comment.value.bytes = (BYTE *)"comment";
1952 comment.value.length = sizeof("comment") - 1;
1953 hr = WsWriteNode( writer, &comment.node, NULL );
1954 ok( hr == S_OK, "got %08x\n", hr );
1956 node.nodeType = WS_XML_NODE_TYPE_EOF;
1957 hr = WsWriteNode( writer, &node, NULL );
1958 ok( hr == S_OK, "got %08x\n", hr );
1960 node.nodeType = WS_XML_NODE_TYPE_BOF;
1961 hr = WsWriteNode( writer, &node, NULL );
1962 ok( hr == S_OK, "got %08x\n", hr );
1964 node.nodeType = WS_XML_NODE_TYPE_CDATA;
1965 hr = WsWriteNode( writer, &node, NULL );
1966 ok( hr == S_OK, "got %08x\n", hr );
1968 utf8.value.bytes = (BYTE *)"cdata";
1969 utf8.value.length = sizeof("cdata") - 1;
1970 text.text = &utf8.text;
1971 hr = WsWriteNode( writer, &text.node, NULL );
1972 ok( hr == S_OK, "got %08x\n", hr );
1974 node.nodeType = WS_XML_NODE_TYPE_END_CDATA;
1975 hr = WsWriteNode( writer, &node, NULL );
1976 ok( hr == S_OK, "got %08x\n", hr );
1978 utf8.value.bytes = (BYTE *)"text";
1979 utf8.value.length = sizeof("text") - 1;
1980 hr = WsWriteNode( writer, &text.node, NULL );
1981 ok( hr == S_OK, "got %08x\n", hr );
1983 node.nodeType = WS_XML_NODE_TYPE_END_ELEMENT;
1984 hr = WsWriteNode( writer, &node, NULL );
1985 ok( hr == S_OK, "got %08x\n", hr );
1986 check_output_buffer( buffer, "<t attr='value'><!--comment--><![CDATA[cdata]]>text</t>", __LINE__ );
1988 WsFreeWriter( writer );
1989 WsFreeHeap( heap );
1992 static HRESULT set_input( WS_XML_READER *reader, const char *data, ULONG size )
1994 WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_AUTO};
1995 WS_XML_READER_BUFFER_INPUT buf = {{WS_XML_READER_INPUT_TYPE_BUFFER}, (void *)data, size};
1996 return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
1999 static void test_WsCopyNode(void)
2001 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"}, ns = {0, NULL};
2002 WS_XML_NODE_POSITION pos, pos2;
2003 const WS_XML_NODE *node;
2004 WS_XML_WRITER *writer;
2005 WS_XML_READER *reader;
2006 WS_XML_BUFFER *buffer;
2007 WS_BUFFERS bufs;
2008 WS_HEAP *heap;
2009 HRESULT hr;
2011 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
2012 ok( hr == S_OK, "got %08x\n", hr );
2014 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2015 ok( hr == S_OK, "got %08x\n", hr );
2017 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
2018 ok( hr == S_OK, "got %08x\n", hr );
2020 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
2021 ok( hr == S_OK, "got %08x\n", hr );
2023 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2024 ok( hr == S_OK, "got %08x\n", hr );
2026 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
2027 ok( hr == S_OK, "got %08x\n", hr );
2029 hr = WsWriteEndElement( writer, NULL );
2030 ok( hr == S_OK, "got %08x\n", hr );
2032 hr = WsGetWriterPosition( writer, &pos, NULL );
2033 ok( hr == S_OK, "got %08x\n", hr );
2035 hr = WsWriteEndElement( writer, NULL );
2036 ok( hr == S_OK, "got %08x\n", hr );
2037 check_output_buffer( buffer, "<t><u/></t>", __LINE__ );
2039 hr = WsCreateReader( NULL, 0, &reader, NULL );
2040 ok( hr == S_OK, "got %08x\n", hr );
2042 hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
2043 ok( hr == S_OK, "got %08x\n", hr );
2045 hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
2046 ok( hr == S_OK, "got %08x\n", hr );
2048 hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
2049 ok( hr == S_OK, "got %08x\n", hr );
2051 hr = WsSetWriterPosition( writer, &pos, NULL );
2052 ok( hr == S_OK, "got %08x\n", hr );
2054 hr = WsCopyNode( writer, reader, NULL );
2055 ok( hr == S_OK, "got %08x\n", hr );
2056 check_output_buffer( buffer, "<t><u/><v/></t>", __LINE__ );
2058 hr = WsGetWriterPosition( writer, &pos2, NULL );
2059 ok( hr == S_OK, "got %08x\n", hr );
2060 ok( pos2.buffer == pos.buffer, "wrong buffer\n" );
2061 ok( pos2.node == pos.node, "wrong node\n" );
2063 hr = WsGetReaderNode( reader, &node, NULL );
2064 ok( hr == S_OK, "got %08x\n", hr );
2065 ok( node->nodeType == WS_XML_NODE_TYPE_EOF, "got %u\n", node->nodeType );
2067 /* reader positioned at EOF */
2068 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
2069 ok( hr == S_OK, "got %08x\n", hr );
2071 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
2072 ok( hr == S_OK, "got %08x\n", hr );
2074 hr = WsCopyNode( writer, reader, NULL );
2075 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2077 /* reader positioned at BOF */
2078 hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
2079 ok( hr == S_OK, "got %08x\n", hr );
2081 hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
2082 ok( hr == S_OK, "got %08x\n", hr );
2084 hr = WsGetReaderNode( reader, &node, NULL );
2085 ok( hr == S_OK, "got %08x\n", hr );
2086 ok( node->nodeType == WS_XML_NODE_TYPE_BOF, "got %u\n", node->nodeType );
2088 hr = set_output( writer );
2089 ok( hr == S_OK, "got %08x\n", hr );
2091 hr = WsCopyNode( writer, reader, NULL );
2092 ok( hr == S_OK, "got %08x\n", hr );
2093 check_output( writer, "<v/>", __LINE__ );
2095 hr = WsGetReaderNode( reader, &node, NULL );
2096 ok( hr == S_OK, "got %08x\n", hr );
2097 ok( node->nodeType == WS_XML_NODE_TYPE_EOF, "got %u\n", node->nodeType );
2099 memset( &bufs, 0, sizeof(bufs) );
2100 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFERS, &bufs, sizeof(bufs), NULL );
2101 ok( hr == S_OK, "got %08x\n", hr );
2102 ok( bufs.bufferCount == 1, "got %u\n", bufs.bufferCount );
2103 ok( bufs.buffers != NULL, "buffers not set\n" );
2105 /* reader positioned at BOF, single text node */
2106 hr = set_input( reader, "text", sizeof("text") - 1 );
2107 ok( hr == S_OK, "got %08x\n", hr );
2109 hr = WsGetReaderNode( reader, &node, NULL );
2110 ok( hr == S_OK, "got %08x\n", hr );
2111 ok( node->nodeType == WS_XML_NODE_TYPE_BOF, "got %u\n", node->nodeType );
2113 hr = set_output( writer );
2114 ok( hr == S_OK, "got %08x\n", hr );
2116 hr = WsCopyNode( writer, reader, NULL );
2117 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
2119 WsFreeReader( reader );
2120 WsFreeWriter( writer );
2121 WsFreeHeap( heap );
2124 static void test_text_types(void)
2126 static const WCHAR utf16W[] = {'u','t','f','1','6'};
2127 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"};
2128 WS_XML_STRING ns = {0, NULL}, ns2 = {2, (BYTE *)"ns"};
2129 WS_XML_WRITER *writer;
2130 static const WS_XML_UTF8_TEXT val_utf8 = { {WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"utf8"} };
2131 static WS_XML_UTF16_TEXT val_utf16 = { {WS_XML_TEXT_TYPE_UTF16} };
2132 static WS_XML_QNAME_TEXT val_qname = { {WS_XML_TEXT_TYPE_QNAME} };
2133 static const WS_XML_GUID_TEXT val_guid = { {WS_XML_TEXT_TYPE_GUID} };
2134 static const WS_XML_UNIQUE_ID_TEXT val_urn = { {WS_XML_TEXT_TYPE_UNIQUE_ID} };
2135 static const WS_XML_BOOL_TEXT val_bool = { {WS_XML_TEXT_TYPE_BOOL}, TRUE };
2136 static const WS_XML_INT32_TEXT val_int32 = { {WS_XML_TEXT_TYPE_INT32}, -2147483647 - 1 };
2137 static const WS_XML_INT64_TEXT val_int64 = { {WS_XML_TEXT_TYPE_INT64}, -9223372036854775807 - 1 };
2138 static const WS_XML_UINT64_TEXT val_uint64 = { {WS_XML_TEXT_TYPE_UINT64}, ~0 };
2139 static const WS_XML_DATETIME_TEXT val_datetime = { {WS_XML_TEXT_TYPE_DATETIME}, {0, WS_DATETIME_FORMAT_UTC} };
2140 static const WS_XML_DOUBLE_TEXT val_double = { {WS_XML_TEXT_TYPE_DOUBLE}, 1.1 };
2141 static const WS_XML_BASE64_TEXT val_base64 = { {WS_XML_TEXT_TYPE_BASE64}, (BYTE *)"test", 4 };
2142 static const struct
2144 const WS_XML_TEXT *text;
2145 const char *result;
2147 tests[] =
2149 { &val_utf8.text, "<t>utf8</t>" },
2150 { &val_utf16.text, "<t>utf16</t>" },
2151 { &val_guid.text, "<t>00000000-0000-0000-0000-000000000000</t>" },
2152 { &val_urn.text, "<t>urn:uuid:00000000-0000-0000-0000-000000000000</t>" },
2153 { &val_bool.text, "<t>true</t>" },
2154 { &val_int32.text, "<t>-2147483648</t>" },
2155 { &val_int64.text, "<t>-9223372036854775808</t>" },
2156 { &val_uint64.text, "<t>18446744073709551615</t>" },
2157 { &val_datetime.text, "<t>0001-01-01T00:00:00Z</t>" },
2158 { &val_double.text, "<t>1.1</t>" },
2159 { &val_base64.text, "<t>dGVzdA==</t>" },
2160 { &val_qname.text, "<t>u</t>" },
2162 HRESULT hr;
2163 ULONG i;
2165 val_utf16.bytes = (BYTE *)utf16W;
2166 val_utf16.byteCount = sizeof(utf16W);
2167 val_qname.localName = &localname2;
2168 val_qname.ns = &ns;
2170 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2171 ok( hr == S_OK, "got %08x\n", hr );
2173 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2175 hr = set_output( writer );
2176 ok( hr == S_OK, "got %08x\n", hr );
2177 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2178 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2180 hr = WsWriteText( writer, tests[i].text, NULL );
2181 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2183 hr = WsWriteEndElement( writer, NULL );
2184 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2185 check_output( writer, tests[i].result, __LINE__ );
2188 hr = set_output( writer );
2189 ok( hr == S_OK, "got %08x\n", hr );
2190 hr = WsWriteStartElement( writer, &prefix, &localname, &ns2, NULL );
2191 ok( hr == S_OK, "got %08x\n", hr );
2193 val_qname.prefix = &prefix;
2194 val_qname.localName = &localname2;
2195 val_qname.ns = &ns2;
2196 hr = WsWriteText( writer, &val_qname.text, NULL );
2197 ok( hr == S_OK, "got %08x\n", hr );
2199 hr = WsWriteEndElement( writer, NULL );
2200 ok( hr == S_OK, "got %08x\n", hr );
2201 check_output( writer, "<p:t xmlns:p=\"ns\">p:u</p:t>", __LINE__ );
2203 WsFreeWriter( writer );
2206 static BOOL get_fpword( unsigned short *ret )
2208 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2209 unsigned short fpword;
2210 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
2211 *ret = fpword;
2212 return TRUE;
2213 #endif
2214 return FALSE;
2217 static void set_fpword( unsigned short fpword )
2219 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2220 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2221 #endif
2224 static void test_double(void)
2226 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2227 unsigned short fpword;
2228 static const struct
2230 double val;
2231 const char *result;
2233 tests[] =
2235 {0.0, "<t>0</t>"},
2236 {1.0, "<t>1</t>"},
2237 {-1.0, "<t>-1</t>"},
2238 {1.0000000000000001, "<t>1</t>"},
2239 {1.0000000000000002, "<t>1.0000000000000002</t>"},
2240 {1.0000000000000003, "<t>1.0000000000000002</t>"},
2241 {1.0000000000000004, "<t>1.0000000000000004</t>"},
2242 {100000000000000, "<t>100000000000000</t>"},
2243 {1000000000000000, "<t>1E+15</t>"},
2244 {0.1, "<t>0.1</t>"},
2245 {0.01, "<t>1E-2</t>"},
2246 {-0.1, "<t>-0.1</t>"},
2247 {-0.01, "<t>-1E-2</t>"},
2248 {1.7976931348623158e308, "<t>1.7976931348623157E+308</t>"},
2249 {-1.7976931348623158e308, "<t>-1.7976931348623157E+308</t>"},
2251 HRESULT hr;
2252 WS_XML_WRITER *writer;
2253 WS_XML_DOUBLE_TEXT text;
2254 ULONG i;
2256 hr = WsCreateWriter( NULL, 0, &writer, NULL ) ;
2257 ok( hr == S_OK, "got %08x\n", hr );
2259 text.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
2260 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2262 hr = set_output( writer );
2263 ok( hr == S_OK, "got %08x\n", hr );
2264 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2265 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2267 text.value = tests[i].val;
2268 hr = WsWriteText( writer, &text.text, NULL );
2269 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2271 hr = WsWriteEndElement( writer, NULL );
2272 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2273 check_output( writer, tests[i].result, __LINE__ );
2276 hr = set_output( writer );
2277 ok( hr == S_OK, "got %08x\n", hr );
2278 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2279 ok( hr == S_OK, "got %08x\n", hr );
2281 text.value = NAN;
2282 hr = WsWriteText( writer, &text.text, NULL );
2283 ok( hr == S_OK, "got %08x\n", hr );
2285 hr = WsWriteEndElement( writer, NULL );
2286 ok( hr == S_OK, "got %08x\n", hr );
2287 check_output( writer, "<t>NaN</t>", __LINE__ );
2289 hr = set_output( writer );
2290 ok( hr == S_OK, "got %08x\n", hr );
2291 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2292 ok( hr == S_OK, "got %08x\n", hr );
2294 text.value = INFINITY;
2295 hr = WsWriteText( writer, &text.text, NULL );
2296 ok( hr == S_OK, "got %08x\n", hr );
2298 hr = WsWriteEndElement( writer, NULL );
2299 ok( hr == S_OK, "got %08x\n", hr );
2300 check_output( writer, "<t>INF</t>", __LINE__ );
2302 hr = set_output( writer );
2303 ok( hr == S_OK, "got %08x\n", hr );
2304 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2305 ok( hr == S_OK, "got %08x\n", hr );
2307 text.value = -INFINITY;
2308 hr = WsWriteText( writer, &text.text, NULL );
2309 ok( hr == S_OK, "got %08x\n", hr );
2311 hr = WsWriteEndElement( writer, NULL );
2312 ok( hr == S_OK, "got %08x\n", hr );
2313 check_output( writer, "<t>-INF</t>", __LINE__ );
2315 if (!get_fpword( &fpword ))
2317 skip( "can't get floating point control word\n" );
2318 WsFreeWriter( writer );
2319 return;
2321 ok( fpword == 0x27f, "got %04x\n", fpword );
2322 set_fpword( 0x1f7f );
2323 get_fpword( &fpword );
2324 ok( fpword == 0x1f7f, "got %04x\n", fpword );
2326 hr = set_output( writer );
2327 ok( hr == S_OK, "got %08x\n", hr );
2328 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2329 ok( hr == S_OK, "got %08x\n", hr );
2331 text.value = 100000000000000;
2332 hr = WsWriteText( writer, &text.text, NULL );
2333 ok( hr == S_OK, "got %08x\n", hr );
2335 hr = WsWriteEndElement( writer, NULL );
2336 ok( hr == S_OK, "got %08x\n", hr );
2337 check_output( writer, "<t>100000000000000</t>", __LINE__ );
2339 get_fpword( &fpword );
2340 ok( fpword == 0x1f7f, "got %04x\n", fpword );
2341 set_fpword( 0x27f );
2343 WsFreeWriter( writer );
2346 static void test_field_options(void)
2348 static const char expected[] =
2349 "<t><bool a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/><int32>-1</int32>"
2350 "<xmlstr a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/></t>";
2351 HRESULT hr;
2352 WS_XML_WRITER *writer;
2353 WS_STRUCT_DESCRIPTION s;
2354 WS_FIELD_DESCRIPTION f, f2, f3, f4, f5, *fields[5];
2355 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, str_guid = {4, (BYTE *)"guid"};
2356 WS_XML_STRING str_int32 = {5, (BYTE *)"int32"}, str_bool = {4, (BYTE *)"bool"};
2357 WS_XML_STRING str_xmlstr = {6, (BYTE *)"xmlstr"}, str_str = {3, (BYTE *)"str"};
2358 INT32 val = -1;
2359 struct test
2361 GUID guid;
2362 BOOL *bool_ptr;
2363 INT32 *int32_ptr;
2364 WS_XML_STRING xmlstr;
2365 WCHAR *str;
2366 } test;
2368 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2369 ok( hr == S_OK, "got %08x\n", hr );
2371 hr = set_output( writer );
2372 ok( hr == S_OK, "got %08x\n", hr );
2374 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2375 ok( hr == S_OK, "got %08x\n", hr );
2377 memset( &f, 0, sizeof(f) );
2378 f.mapping = WS_ELEMENT_FIELD_MAPPING;
2379 f.localName = &str_guid;
2380 f.ns = &ns;
2381 f.type = WS_GUID_TYPE;
2382 f.options = WS_FIELD_OPTIONAL;
2383 fields[0] = &f;
2385 memset( &f2, 0, sizeof(f2) );
2386 f2.mapping = WS_ELEMENT_FIELD_MAPPING;
2387 f2.localName = &str_bool;
2388 f2.offset = FIELD_OFFSET(struct test, bool_ptr);
2389 f2.ns = &ns;
2390 f2.type = WS_BOOL_TYPE;
2391 f2.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2392 fields[1] = &f2;
2394 memset( &f3, 0, sizeof(f3) );
2395 f3.mapping = WS_ELEMENT_FIELD_MAPPING;
2396 f3.localName = &str_int32;
2397 f3.offset = FIELD_OFFSET(struct test, int32_ptr);
2398 f3.ns = &ns;
2399 f3.type = WS_INT32_TYPE;
2400 f3.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2401 fields[2] = &f3;
2403 memset( &f4, 0, sizeof(f4) );
2404 f4.mapping = WS_ELEMENT_FIELD_MAPPING;
2405 f4.localName = &str_xmlstr;
2406 f4.offset = FIELD_OFFSET(struct test, xmlstr);
2407 f4.ns = &ns;
2408 f4.type = WS_XML_STRING_TYPE;
2409 f4.options = WS_FIELD_NILLABLE;
2410 fields[3] = &f4;
2412 memset( &f5, 0, sizeof(f5) );
2413 f5.mapping = WS_ELEMENT_FIELD_MAPPING;
2414 f5.localName = &str_str;
2415 f5.offset = FIELD_OFFSET(struct test, str);
2416 f5.ns = &ns;
2417 f5.type = WS_WSZ_TYPE;
2418 f5.options = WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE;
2419 fields[4] = &f5;
2421 memset( &s, 0, sizeof(s) );
2422 s.size = sizeof(struct test);
2423 s.alignment = TYPE_ALIGNMENT(struct test);
2424 s.fields = fields;
2425 s.fieldCount = 5;
2427 memset( &test, 0, sizeof(test) );
2428 test.int32_ptr = &val;
2429 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
2430 &test, sizeof(test), NULL );
2431 ok( hr == S_OK, "got %08x\n", hr );
2433 hr = WsWriteEndElement( writer, NULL );
2434 ok( hr == S_OK, "got %08x\n", hr );
2435 check_output( writer, expected, __LINE__ );
2437 WsFreeWriter( writer );
2440 static void test_WsWriteText(void)
2442 static const WCHAR testW[] = {'t','e','s','t'};
2443 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
2444 HRESULT hr;
2445 WS_XML_WRITER *writer;
2446 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2447 WS_XML_UTF16_TEXT utf16 = {{WS_XML_TEXT_TYPE_UTF16}};
2448 WS_XML_GUID_TEXT guid = {{WS_XML_TEXT_TYPE_GUID}};
2450 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2451 ok( hr == S_OK, "got %08x\n", hr );
2453 hr = set_output( writer );
2454 ok( hr == S_OK, "got %08x\n", hr );
2456 utf8.value.bytes = (BYTE *)"test";
2457 utf8.value.length = 4;
2458 hr = WsWriteText( writer, &utf8.text, NULL );
2459 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
2461 hr = set_output( writer );
2462 ok( hr == S_OK, "got %08x\n", hr );
2464 /* element, utf8 */
2465 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2466 ok( hr == S_OK, "got %08x\n", hr );
2468 hr = WsWriteText( writer, &utf8.text, NULL );
2469 ok( hr == S_OK, "got %08x\n", hr );
2470 check_output( writer, "<t>test", __LINE__ );
2472 utf8.value.bytes = (BYTE *)"tset";
2473 hr = WsWriteText( writer, &utf8.text, NULL );
2474 ok( hr == S_OK, "got %08x\n", hr );
2475 check_output( writer, "<t>testtset", __LINE__ );
2477 hr = WsWriteEndElement( writer, NULL );
2478 ok( hr == S_OK, "got %08x\n", hr );
2479 check_output( writer, "<t>testtset</t>", __LINE__ );
2481 hr = set_output( writer );
2482 ok( hr == S_OK, "got %08x\n", hr );
2484 /* attribute, utf8 */
2485 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2486 ok( hr == S_OK, "got %08x\n", hr );
2488 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2489 ok( hr == S_OK, "got %08x\n", hr );
2491 hr = WsWriteText( writer, &utf8.text, NULL );
2492 ok( hr == S_OK, "got %08x\n", hr );
2493 check_output( writer, "", __LINE__ );
2495 utf8.value.bytes = (BYTE *)"test";
2496 hr = WsWriteText( writer, &utf8.text, NULL );
2497 ok( hr == S_OK, "got %08x\n", hr );
2498 check_output( writer, "", __LINE__ );
2500 hr = WsWriteEndAttribute( writer, NULL );
2501 ok( hr == S_OK, "got %08x\n", hr );
2503 hr = WsWriteEndElement( writer, NULL );
2504 ok( hr == S_OK, "got %08x\n", hr );
2505 check_output( writer, "<t a=\"tsettest\"/>", __LINE__ );
2507 hr = set_output( writer );
2508 ok( hr == S_OK, "got %08x\n", hr );
2510 /* element, utf16 */
2511 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2512 ok( hr == S_OK, "got %08x\n", hr );
2514 utf16.bytes = (BYTE *)testW;
2515 utf16.byteCount = sizeof(testW);
2516 hr = WsWriteText( writer, &utf16.text, NULL );
2517 ok( hr == S_OK, "got %08x\n", hr );
2518 check_output( writer, "<t>test", __LINE__ );
2520 hr = WsWriteText( writer, &utf16.text, NULL );
2521 ok( hr == S_OK, "got %08x\n", hr );
2522 check_output( writer, "<t>testtest", __LINE__ );
2524 hr = WsWriteEndElement( writer, NULL );
2525 ok( hr == S_OK, "got %08x\n", hr );
2526 check_output( writer, "<t>testtest</t>", __LINE__ );
2528 hr = set_output( writer );
2529 ok( hr == S_OK, "got %08x\n", hr );
2531 /* attribute, utf16 */
2532 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2533 ok( hr == S_OK, "got %08x\n", hr );
2535 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2536 ok( hr == S_OK, "got %08x\n", hr );
2538 hr = WsWriteText( writer, &utf16.text, NULL );
2539 ok( hr == S_OK, "got %08x\n", hr );
2540 check_output( writer, "", __LINE__ );
2542 hr = WsWriteText( writer, &utf16.text, NULL );
2543 ok( hr == S_OK, "got %08x\n", hr );
2544 check_output( writer, "", __LINE__ );
2546 hr = WsWriteEndAttribute( writer, NULL );
2547 ok( hr == S_OK, "got %08x\n", hr );
2549 hr = WsWriteEndElement( writer, NULL );
2550 ok( hr == S_OK, "got %08x\n", hr );
2551 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
2553 hr = set_output( writer );
2554 ok( hr == S_OK, "got %08x\n", hr );
2556 /* element, guid */
2557 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2558 ok( hr == S_OK, "got %08x\n", hr );
2560 hr = WsWriteText( writer, &guid.text, NULL );
2561 ok( hr == S_OK, "got %08x\n", hr );
2562 check_output( writer, "<t>00000000-0000-0000-0000-000000000000", __LINE__ );
2564 hr = WsWriteText( writer, &guid.text, NULL );
2565 ok( hr == S_OK, "got %08x\n", hr );
2566 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000",
2567 __LINE__ );
2569 /* continue with different text type */
2570 hr = WsWriteText( writer, &utf8.text, NULL );
2571 ok( hr == S_OK, "got %08x\n", hr );
2572 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000test",
2573 __LINE__ );
2575 hr = WsWriteEndElement( writer, NULL );
2576 ok( hr == S_OK, "got %08x\n", hr );
2578 hr = set_output( writer );
2579 ok( hr == S_OK, "got %08x\n", hr );
2581 /* attribute, guid */
2582 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2583 ok( hr == S_OK, "got %08x\n", hr );
2585 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2586 ok( hr == S_OK, "got %08x\n", hr );
2588 hr = WsWriteText( writer, &guid.text, NULL );
2589 ok( hr == S_OK, "got %08x\n", hr );
2590 check_output( writer, "", __LINE__ );
2592 hr = WsWriteText( writer, &guid.text, NULL );
2593 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2595 hr = set_output( writer );
2596 ok( hr == S_OK, "got %08x\n", hr );
2598 /* attribute, mix allowed text types */
2599 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2600 ok( hr == S_OK, "got %08x\n", hr );
2602 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2603 ok( hr == S_OK, "got %08x\n", hr );
2605 hr = WsWriteText( writer, &utf8.text, NULL );
2606 ok( hr == S_OK, "got %08x\n", hr );
2608 hr = WsWriteText( writer, &utf16.text, NULL );
2609 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2611 hr = set_output( writer );
2612 ok( hr == S_OK, "got %08x\n", hr );
2614 /* cdata */
2615 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2616 ok( hr == S_OK, "got %08x\n", hr );
2617 hr = WsWriteStartCData( writer, NULL );
2618 ok( hr == S_OK, "got %08x\n", hr );
2620 hr = WsWriteText( writer, &utf8.text, NULL );
2621 ok( hr == S_OK, "got %08x\n", hr );
2623 hr = WsWriteText( writer, &guid.text, NULL );
2624 ok( hr == S_OK, "got %08x\n", hr );
2626 hr = WsWriteEndCData( writer, NULL );
2627 ok( hr == S_OK, "got %08x\n", hr );
2628 hr = WsWriteEndElement( writer, NULL );
2629 ok( hr == S_OK, "got %08x\n", hr );
2630 check_output( writer, "<t><![CDATA[test00000000-0000-0000-0000-000000000000]]></t>", __LINE__ );
2632 WsFreeWriter( writer );
2635 static void test_WsWriteArray(void)
2637 static const WS_XML_STRING localname = {4, (BYTE *)"item"}, localname2 = {5, (BYTE *)"array"};
2638 static const WS_XML_STRING ns = {0, NULL};
2639 WS_XML_WRITER *writer;
2640 BOOL array_bool[2];
2641 HRESULT hr;
2643 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2644 ok( hr == S_OK, "got %08x\n", hr );
2646 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2647 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2649 hr = set_output( writer );
2650 ok( hr == S_OK, "got %08x\n", hr );
2651 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2652 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2654 hr = set_output( writer );
2655 ok( hr == S_OK, "got %08x\n", hr );
2656 hr = WsWriteArray( writer, &localname, NULL, 0, NULL, 0, 0, 0, NULL );
2657 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2659 hr = set_output( writer );
2660 ok( hr == S_OK, "got %08x\n", hr );
2661 hr = WsWriteArray( writer, &localname, &ns, 0, NULL, 0, 0, 0, NULL );
2662 ok( hr == S_OK, "got %08x\n", hr );
2663 check_output( writer, "", __LINE__ );
2665 hr = WsWriteArray( writer, &localname, &ns, ~0u, NULL, 0, 0, 0, NULL );
2666 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2668 hr = set_output( writer );
2669 ok( hr == S_OK, "got %08x\n", hr );
2670 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, 0, 0, 0, NULL );
2671 ok( hr == S_OK, "got %08x\n", hr );
2672 check_output( writer, "", __LINE__ );
2674 array_bool[0] = FALSE;
2675 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, 0, 0, 0, NULL );
2676 ok( hr == S_OK, "got %08x\n", hr );
2677 check_output( writer, "", __LINE__ );
2679 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 0, NULL );
2680 ok( hr == S_OK, "got %08x\n", hr );
2681 check_output( writer, "", __LINE__ );
2683 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 0, NULL );
2684 ok( hr == S_OK, "got %08x\n", hr );
2685 check_output( writer, "", __LINE__ );
2687 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 1, NULL );
2688 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2690 hr = set_output( writer );
2691 ok( hr == S_OK, "got %08x\n", hr );
2692 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 1, NULL );
2693 ok( hr == S_OK, "got %08x\n", hr );
2694 check_output( writer, "<item>false</item>", __LINE__ );
2696 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool) - 1, 0, 2, NULL );
2697 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2699 hr = set_output( writer );
2700 ok( hr == S_OK, "got %08x\n", hr );
2701 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 3, NULL );
2702 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2704 hr = set_output( writer );
2705 ok( hr == S_OK, "got %08x\n", hr );
2707 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
2708 ok( hr == S_OK, "got %08x\n", hr );
2710 array_bool[1] = TRUE;
2711 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 2, NULL );
2712 ok( hr == S_OK, "got %08x\n", hr );
2714 hr = WsWriteEndElement( writer, NULL );
2715 ok( hr == S_OK, "got %08x\n", hr );
2716 check_output( writer, "<array><item>false</item><item>true</item></array>", __LINE__ );
2718 WsFreeWriter( writer );
2721 static void test_escapes(void)
2723 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2724 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2725 WS_XML_WRITER *writer;
2726 struct test
2728 const char *text;
2729 const char *result;
2730 BOOL single;
2732 static const struct test tests_elem[] =
2734 { "<", "<t>&lt;</t>" },
2735 { ">", "<t>&gt;</t>" },
2736 { "\"", "<t>\"</t>" },
2737 { "&", "<t>&amp;</t>" },
2738 { "&&", "<t>&amp;&amp;</t>" },
2739 { "'", "<t>'</t>" },
2741 static const struct test tests_attr[] =
2743 { "<", "<t t=\"&lt;\"/>" },
2744 { ">", "<t t=\">\"/>" },
2745 { "\"", "<t t=\"&quot;\"/>" },
2746 { "&", "<t t=\"&amp;\"/>" },
2747 { "'", "<t t=\"'\"/>" },
2748 { "\"", "<t t='\"'/>", TRUE },
2749 { "'", "<t t='&apos;'/>", TRUE },
2751 static const struct test tests_cdata[] =
2753 { "<", "<t><![CDATA[<]]></t>" },
2754 { ">", "<t><![CDATA[>]]></t>" },
2755 { "\"", "<t><![CDATA[\"]]></t>" },
2756 { "&", "<t><![CDATA[&]]></t>" },
2757 { "[", "<t><![CDATA[[]]></t>" },
2758 { "]", "<t><![CDATA[]]]></t>" },
2759 { "'", "<t><![CDATA[']]></t>" },
2761 static const struct test tests_comment[] =
2763 { "<", "<t><!--<--></t>" },
2764 { ">", "<t><!-->--></t>" },
2765 { "\"", "<t><!--\"--></t>" },
2766 { "&", "<t><!--&--></t>" },
2767 { "'", "<t><!--'--></t>" },
2769 HRESULT hr;
2770 ULONG i;
2772 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2773 ok( hr == S_OK, "got %08x\n", hr );
2775 for (i = 0; i < ARRAY_SIZE( tests_elem ); i++)
2777 hr = set_output( writer );
2778 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2779 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2780 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2782 utf8.value.bytes = (BYTE *)tests_elem[i].text;
2783 utf8.value.length = strlen( tests_elem[i].text );
2784 hr = WsWriteText( writer, &utf8.text, NULL );
2785 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2787 hr = WsWriteEndElement( writer, NULL );
2788 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2789 check_output( writer, tests_elem[i].result, __LINE__ );
2792 for (i = 0; i < ARRAY_SIZE( tests_attr ); i++)
2794 hr = set_output( writer );
2795 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2796 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2797 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2799 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, tests_attr[i].single, NULL );
2800 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2802 utf8.value.bytes = (BYTE *)tests_attr[i].text;
2803 utf8.value.length = strlen( tests_attr[i].text );
2804 hr = WsWriteText( writer, &utf8.text, NULL );
2805 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2807 hr = WsWriteEndAttribute( writer, NULL );
2808 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2810 hr = WsWriteEndElement( writer, NULL );
2811 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2812 check_output( writer, tests_attr[i].result, __LINE__ );
2815 for (i = 0; i < ARRAY_SIZE( tests_cdata ); i++)
2817 hr = set_output( writer );
2818 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2819 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2820 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2822 hr = WsWriteStartCData( writer, NULL );
2823 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2825 utf8.value.bytes = (BYTE *)tests_cdata[i].text;
2826 utf8.value.length = strlen( tests_cdata[i].text );
2827 hr = WsWriteText( writer, &utf8.text, NULL );
2828 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2830 hr = WsWriteEndCData( writer, NULL );
2831 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2833 hr = WsWriteEndElement( writer, NULL );
2834 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2835 check_output( writer, tests_cdata[i].result, __LINE__ );
2838 for (i = 0; i < ARRAY_SIZE( tests_comment ); i++)
2840 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
2842 hr = set_output( writer );
2843 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2844 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2845 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2847 comment.value.bytes = (BYTE *)tests_comment[i].text;
2848 comment.value.length = strlen( tests_comment[i].text );
2849 hr = WsWriteNode( writer, &comment.node, NULL );
2850 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2852 hr = WsWriteEndElement( writer, NULL );
2853 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2854 check_output( writer, tests_comment[i].result, __LINE__ );
2857 WsFreeWriter( writer );
2860 static void test_write_option(void)
2862 static const WCHAR sW[] = {'s',0};
2863 static const WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2864 WS_XML_WRITER *writer;
2865 int val_int = -1, val_int_zero = 0, *ptr_int = &val_int, *ptr_int_null = NULL;
2866 const WCHAR *ptr_wsz = sW, *ptr_wsz_null = NULL;
2867 static const WS_XML_STRING val_xmlstr = {1, (BYTE *)"x"}, val_xmlstr_zero = {0, NULL};
2868 const WS_XML_STRING *ptr_xmlstr = &val_xmlstr, *ptr_xmlstr_null = NULL;
2869 struct
2871 WS_TYPE type;
2872 WS_WRITE_OPTION option;
2873 const void *value;
2874 ULONG size;
2875 HRESULT hr;
2876 const char *result;
2878 tests[] =
2880 { WS_INT32_TYPE, 0, NULL, 0, E_INVALIDARG },
2881 { WS_INT32_TYPE, 0, "str", 0, E_INVALIDARG },
2882 { WS_INT32_TYPE, 0, NULL, sizeof(val_int), E_INVALIDARG },
2883 { WS_INT32_TYPE, 0, &val_int, sizeof(val_int), E_INVALIDARG },
2884 { WS_INT32_TYPE, 0, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2885 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2886 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, 0, E_INVALIDARG },
2887 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2888 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, sizeof(val_int), S_OK, "<t>-1</t>" },
2889 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int_zero, sizeof(val_int_zero), S_OK, "<t>0</t>" },
2890 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, 0, E_INVALIDARG },
2891 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, 0, E_INVALIDARG },
2892 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2893 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, sizeof(val_int), E_INVALIDARG },
2894 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2895 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2896 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, 0, E_INVALIDARG },
2897 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2898 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2899 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int_null, sizeof(ptr_int_null), E_INVALIDARG },
2900 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2901 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, 0, E_INVALIDARG },
2902 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2903 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2904 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int_null, sizeof(ptr_int_null), S_OK,
2905 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2906 { WS_XML_STRING_TYPE, 0, NULL, 0, E_INVALIDARG },
2907 { WS_XML_STRING_TYPE, 0, &val_xmlstr, 0, E_INVALIDARG },
2908 { WS_XML_STRING_TYPE, 0, NULL, sizeof(val_xmlstr), E_INVALIDARG },
2909 { WS_XML_STRING_TYPE, 0, &val_xmlstr, sizeof(val_xmlstr), E_INVALIDARG },
2910 { WS_XML_STRING_TYPE, 0, &val_xmlstr_zero, sizeof(val_xmlstr_zero), E_INVALIDARG },
2911 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2912 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2913 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2914 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, sizeof(val_xmlstr), S_OK, "<t>x</t>" },
2915 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, "<t/>" },
2916 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2917 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2918 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, sizeof(&val_xmlstr), E_INVALIDARG },
2919 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK,
2920 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2921 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2922 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2923 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2924 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2925 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), E_INVALIDARG },
2926 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2927 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2928 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2929 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2930 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), S_OK,
2931 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2932 { WS_WSZ_TYPE, 0, NULL, 0, E_INVALIDARG },
2933 { WS_WSZ_TYPE, 0, &ptr_wsz, 0, E_INVALIDARG },
2934 { WS_WSZ_TYPE, 0, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2935 { WS_WSZ_TYPE, 0, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2936 { WS_WSZ_TYPE, 0, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2937 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2938 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2939 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2940 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2941 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2942 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2943 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2944 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2945 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2946 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2947 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2948 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), S_OK,
2949 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2951 HRESULT hr;
2952 ULONG i;
2954 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2955 ok( hr == S_OK, "got %08x\n", hr );
2957 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2959 hr = set_output( writer );
2960 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2961 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2962 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL, tests[i].option, tests[i].value,
2963 tests[i].size, NULL );
2964 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
2965 WsWriteEndElement( writer, NULL );
2966 if (hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
2969 WsFreeWriter( writer );
2972 static BOOL check_result( WS_XML_WRITER *writer, const char *expected )
2974 WS_BYTES bytes;
2975 ULONG size = sizeof(bytes);
2976 int len = strlen( expected );
2978 memset( &bytes, 0, sizeof(bytes) );
2979 WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
2980 if (bytes.length != len) return FALSE;
2981 return !memcmp( bytes.bytes, expected, len );
2984 static void test_datetime(void)
2986 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2987 static const struct
2989 unsigned __int64 ticks;
2990 WS_DATETIME_FORMAT format;
2991 HRESULT hr;
2992 const char *result;
2993 const char *result2;
2994 HRESULT hr_broken;
2996 tests[] =
2998 { 0, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00Z</t>" },
2999 { 0, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00+00:00</t>" },
3000 { 0, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00</t>" },
3001 { 1, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00.0000001Z</t>" },
3002 { 1, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00.0000001+00:00</t>" },
3003 { 1, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.0000001</t>" },
3004 { 10, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.000001</t>" },
3005 { 1000000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.1</t>" },
3006 { 0x23c34600, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:01:00+00:00</t>" },
3007 { 0x861c46800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T01:00:00+00:00</t>" },
3008 { 0x430e234000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T08:00:00+00:00</t>" },
3009 { 0x4b6fe7a800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T09:00:00+00:00</t>" },
3010 { 0x989680, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:01</t>" },
3011 { 0x23c34600, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:01:00</t>" },
3012 { 0x861c46800, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T01:00:00</t>" },
3013 { 0xc92a69c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-02T00:00:00</t>" },
3014 { 0x11ed178c6c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0002-01-01T00:00:00</t>" },
3015 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_UTC, S_OK, "<t>9999-12-31T23:59:59.9999999Z</t>" },
3016 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>9999-12-31T15:59:59.9999999-08:00</t>",
3017 "<t>9999-12-31T17:59:59.9999999-06:00</t>" /* win7 */, WS_E_INVALID_FORMAT },
3018 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_NONE, S_OK, "<t>9999-12-31T23:59:59.9999999</t>" },
3019 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_UTC, WS_E_INVALID_FORMAT },
3020 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_LOCAL, WS_E_INVALID_FORMAT },
3021 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_NONE, WS_E_INVALID_FORMAT },
3022 { 0x8d3123e7df74000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>2015-12-31T16:00:00-08:00</t>",
3023 "<t>2015-12-31T18:00:00-06:00</t>" /* win7 */ },
3024 { 0x701ce1722770000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00+00:00</t>" },
3025 { 0x701ce5a309a4000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00-08:00</t>",
3026 "<t>1601-01-01T02:00:00-06:00</t>" /* win7 */ },
3027 { 0x701ce5e617c7400, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:30:00-08:00</t>",
3028 "<t>1601-01-01T02:30:00-06:00</t>" /* win7 */ },
3029 { 0x701ce51ced5d800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T07:00:00+00:00</t>",
3030 "<t>1601-01-01T01:00:00-06:00</t>" /* win7 */ },
3031 { 0, WS_DATETIME_FORMAT_NONE + 1, WS_E_INVALID_FORMAT },
3032 { 0x38a080649c000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-28T00:00:00Z</t>" },
3033 { 0x38ad130b38000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-29T00:00:00Z</t>" },
3034 { 0x8c1505f0e438000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2000-02-29T00:00:00Z</t>" },
3035 { 0x8d46035e7870000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2017-03-01T00:00:00Z</t>" },
3037 HRESULT hr;
3038 WS_XML_WRITER *writer;
3039 WS_DATETIME date;
3040 ULONG i;
3042 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3043 ok( hr == S_OK, "got %08x\n", hr );
3044 for (i = 0; i < ARRAY_SIZE( tests ); i++)
3046 hr = set_output( writer );
3047 ok( hr == S_OK, "got %08x\n", hr );
3049 date.ticks = tests[i].ticks;
3050 date.format = tests[i].format;
3051 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3052 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_DATETIME_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
3053 &date, sizeof(date), NULL );
3054 WsWriteEndElement( writer, NULL );
3055 ok( hr == tests[i].hr || broken(hr == tests[i].hr_broken), "%u: got %08x\n", i, hr );
3056 if (hr != tests[i].hr && hr == tests[i].hr_broken) break;
3057 if (hr == S_OK)
3059 ok( check_result( writer, tests[i].result ) ||
3060 (tests[i].result2 && broken(check_result( writer, tests[i].result2 ))),
3061 "%u: wrong result\n", i );
3065 WsFreeWriter( writer );
3068 static void test_repeating_element(void)
3070 static const WCHAR oneW[] = {'1',0}, twoW[] = {'2',0};
3071 WS_XML_STRING localname = {4, (BYTE *)"test"}, ns = {0, NULL};
3072 WS_XML_STRING val = {3, (BYTE *)"val"}, wrapper = {7, (BYTE *)"wrapper"};
3073 HRESULT hr;
3074 WS_XML_WRITER *writer;
3075 WS_STRUCT_DESCRIPTION s;
3076 WS_FIELD_DESCRIPTION f, *fields[1];
3077 WS_ITEM_RANGE range;
3078 struct test
3080 const WCHAR **val;
3081 ULONG count;
3082 } *test;
3083 struct test2
3085 INT32 *val;
3086 ULONG count;
3087 } *test2;
3089 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3090 ok( hr == S_OK, "got %08x\n", hr );
3092 /* array of strings, wrapper */
3093 hr = set_output( writer );
3094 ok( hr == S_OK, "got %08x\n", hr );
3095 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3096 ok( hr == S_OK, "got %08x\n", hr );
3098 memset( &f, 0, sizeof(f) );
3099 f.mapping = WS_REPEATING_ELEMENT_FIELD_MAPPING;
3100 f.localName = &wrapper;
3101 f.ns = &ns;
3102 f.type = WS_WSZ_TYPE;
3103 f.countOffset = FIELD_OFFSET(struct test, count);
3104 f.itemLocalName = &val;
3105 f.itemNs = &ns;
3106 fields[0] = &f;
3108 memset( &s, 0, sizeof(s) );
3109 s.size = sizeof(struct test);
3110 s.alignment = TYPE_ALIGNMENT(struct test);
3111 s.typeLocalName = &localname;
3112 s.typeNs = &ns;
3113 s.fields = fields;
3114 s.fieldCount = 1;
3116 hr = set_output( writer );
3117 ok( hr == S_OK, "got %08x\n", hr );
3118 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3119 ok( hr == S_OK, "got %08x\n", hr );
3121 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) + 2 * sizeof(const WCHAR *) );
3122 test->val = (const WCHAR **)(test + 1);
3123 test->val[0] = oneW;
3124 test->val[1] = twoW;
3125 test->count = 2;
3126 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3127 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
3128 ok( hr == S_OK, "got %08x\n", hr );
3129 hr = WsWriteEndElement( writer, NULL );
3130 ok( hr == S_OK, "got %08x\n", hr );
3131 check_output( writer, "<test><wrapper><val>1</val><val>2</val></wrapper></test>", __LINE__ );
3132 HeapFree( GetProcessHeap(), 0, test );
3134 /* array of integers, no wrapper */
3135 hr = set_output( writer );
3136 ok( hr == S_OK, "got %08x\n", hr );
3137 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3138 ok( hr == S_OK, "got %08x\n", hr );
3140 f.type = WS_INT32_TYPE;
3141 f.localName = NULL;
3142 f.ns = NULL;
3144 test2 = HeapAlloc( GetProcessHeap(), 0, sizeof(*test2) + 2 * sizeof(INT32) );
3145 test2->val = (INT32 *)(test2 + 1);
3146 test2->val[0] = 1;
3147 test2->val[1] = 2;
3148 test2->count = 2;
3149 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3150 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3151 ok( hr == S_OK, "got %08x\n", hr );
3152 hr = WsWriteEndElement( writer, NULL );
3153 ok( hr == S_OK, "got %08x\n", hr );
3154 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3156 /* item range has no effect */
3157 hr = set_output( writer );
3158 ok( hr == S_OK, "got %08x\n", hr );
3159 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3160 ok( hr == S_OK, "got %08x\n", hr );
3162 range.minItemCount = 0;
3163 range.maxItemCount = 0;
3164 f.itemRange = &range;
3166 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3167 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3168 ok( hr == S_OK, "got %08x\n", hr );
3169 hr = WsWriteEndElement( writer, NULL );
3170 ok( hr == S_OK, "got %08x\n", hr );
3171 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3172 HeapFree( GetProcessHeap(), 0, test2 );
3174 WsFreeWriter( writer );
3177 static const WS_XML_STRING *init_xmlstring( const char *src, WS_XML_STRING *str )
3179 if (!src) return NULL;
3180 str->length = strlen( src );
3181 str->bytes = (BYTE *)src;
3182 str->dictionary = NULL;
3183 str->id = 0;
3184 return str;
3187 static void test_WsWriteQualifiedName(void)
3189 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
3190 WS_XML_WRITER *writer;
3191 HRESULT hr;
3192 ULONG i;
3193 static const struct
3195 const char *prefix;
3196 const char *localname;
3197 const char *ns;
3198 HRESULT hr;
3199 const char *result;
3200 } tests[] =
3202 { NULL, NULL, NULL, E_INVALIDARG, NULL },
3203 { NULL, "t2", NULL, E_INVALIDARG, NULL },
3204 { "p2", "t2", NULL, S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3205 { NULL, "t2", "ns2", WS_E_INVALID_FORMAT, NULL },
3206 { NULL, "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t2" },
3207 { "p2", "t2", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3208 { "p2", "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3209 { "p", "t", NULL, S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3210 { NULL, "t", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3211 { "p2", "", "", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3212 { "p2", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3213 { "p2", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3214 { "", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">t2" },
3215 { "", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">" },
3216 { "", "", "", S_OK, "<p:t xmlns:p=\"ns\">" },
3219 hr = WsWriteQualifiedName( NULL, NULL, NULL, NULL, NULL );
3220 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3222 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3223 ok( hr == S_OK, "got %08x\n", hr );
3225 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3226 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3228 hr = set_output( writer );
3229 ok( hr == S_OK, "got %08x\n", hr );
3231 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3232 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3234 for (i = 0; i < ARRAY_SIZE( tests ); i++)
3236 WS_XML_STRING prefix2, localname2, ns2;
3237 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3239 hr = set_output( writer );
3240 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3242 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
3243 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3245 prefix_ptr = init_xmlstring( tests[i].prefix, &prefix2 );
3246 localname_ptr = init_xmlstring( tests[i].localname, &localname2 );
3247 ns_ptr = init_xmlstring( tests[i].ns, &ns2 );
3249 hr = WsWriteQualifiedName( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3250 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
3251 if (tests[i].hr == S_OK && hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
3254 WsFreeWriter( writer );
3257 static void test_WsWriteBytes(void)
3259 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3260 WS_XML_WRITER *writer;
3261 HRESULT hr;
3263 hr = WsWriteBytes( NULL, NULL, 0, NULL );
3264 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3266 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3267 ok( hr == S_OK, "got %08x\n", hr );
3269 hr = WsWriteBytes( writer, NULL, 0, NULL );
3270 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3272 hr = WsWriteBytes( writer, "test", 0, NULL );
3273 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3275 hr = WsWriteBytes( writer, NULL, 1, NULL );
3276 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3278 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3279 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3281 hr = set_output( writer );
3282 ok( hr == S_OK, "got %08x\n", hr );
3284 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3285 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3287 hr = set_output( writer );
3288 ok( hr == S_OK, "got %08x\n", hr );
3290 /* element */
3291 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3292 ok( hr == S_OK, "got %08x\n", hr );
3294 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3295 ok( hr == S_OK, "got %08x\n", hr );
3297 hr = WsWriteEndElement( writer, NULL );
3298 ok( hr == S_OK, "got %08x\n", hr );
3299 check_output( writer, "<t>dGVzdAA=</t>", __LINE__ );
3301 hr = set_output( writer );
3302 ok( hr == S_OK, "got %08x\n", hr );
3304 /* attribute */
3305 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3306 ok( hr == S_OK, "got %08x\n", hr );
3308 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3309 ok( hr == S_OK, "got %08x\n", hr );
3311 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3312 ok( hr == S_OK, "got %08x\n", hr );
3314 hr = WsWriteEndAttribute( writer, NULL );
3315 ok( hr == S_OK, "got %08x\n", hr );
3317 hr = WsWriteEndElement( writer, NULL );
3318 ok( hr == S_OK, "got %08x\n", hr );
3319 check_output( writer, "<t a=\"dGVzdAA=\"/>", __LINE__ );
3321 WsFreeWriter( writer );
3324 static void test_WsWriteChars(void)
3326 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3327 static const WCHAR testW[] = {'t','e','s','t'};
3328 WS_XML_WRITER *writer;
3329 HRESULT hr;
3331 hr = WsWriteChars( NULL, NULL, 0, NULL );
3332 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3334 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3335 ok( hr == S_OK, "got %08x\n", hr );
3337 hr = WsWriteChars( writer, NULL, 0, NULL );
3338 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3340 hr = WsWriteChars( writer, testW, 0, NULL );
3341 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3343 hr = WsWriteChars( writer, NULL, 1, NULL );
3344 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3346 hr = WsWriteChars( writer, testW, 4, NULL );
3347 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3349 hr = set_output( writer );
3350 ok( hr == S_OK, "got %08x\n", hr );
3352 hr = WsWriteChars( writer, testW, 4, NULL );
3353 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3355 hr = set_output( writer );
3356 ok( hr == S_OK, "got %08x\n", hr );
3358 /* element */
3359 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3360 ok( hr == S_OK, "got %08x\n", hr );
3362 hr = WsWriteChars( writer, testW, 4, NULL );
3363 ok( hr == S_OK, "got %08x\n", hr );
3365 hr = WsWriteChars( writer, testW, 4, NULL );
3366 ok( hr == S_OK, "got %08x\n", hr );
3368 hr = WsWriteEndElement( writer, NULL );
3369 ok( hr == S_OK, "got %08x\n", hr );
3370 check_output( writer, "<t>testtest</t>", __LINE__ );
3372 hr = set_output( writer );
3373 ok( hr == S_OK, "got %08x\n", hr );
3375 /* attribute */
3376 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3377 ok( hr == S_OK, "got %08x\n", hr );
3379 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3380 ok( hr == S_OK, "got %08x\n", hr );
3382 hr = WsWriteChars( writer, testW, 4, NULL );
3383 ok( hr == S_OK, "got %08x\n", hr );
3385 hr = WsWriteChars( writer, testW, 4, NULL );
3386 ok( hr == S_OK, "got %08x\n", hr );
3388 hr = WsWriteEndAttribute( writer, NULL );
3389 ok( hr == S_OK, "got %08x\n", hr );
3391 hr = WsWriteEndElement( writer, NULL );
3392 ok( hr == S_OK, "got %08x\n", hr );
3393 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3395 WsFreeWriter( writer );
3398 static void test_WsWriteCharsUtf8(void)
3400 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3401 static const BYTE test[] = {'t','e','s','t'};
3402 WS_XML_WRITER *writer;
3403 HRESULT hr;
3405 hr = WsWriteCharsUtf8( NULL, NULL, 0, NULL );
3406 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3408 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3409 ok( hr == S_OK, "got %08x\n", hr );
3411 hr = WsWriteCharsUtf8( writer, NULL, 0, NULL );
3412 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3414 hr = WsWriteCharsUtf8( writer, test, 0, NULL );
3415 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3417 hr = WsWriteCharsUtf8( writer, NULL, 1, NULL );
3418 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3420 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3421 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3423 hr = set_output( writer );
3424 ok( hr == S_OK, "got %08x\n", hr );
3426 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3427 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3429 hr = set_output( writer );
3430 ok( hr == S_OK, "got %08x\n", hr );
3432 /* element */
3433 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3434 ok( hr == S_OK, "got %08x\n", hr );
3436 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3437 ok( hr == S_OK, "got %08x\n", hr );
3439 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3440 ok( hr == S_OK, "got %08x\n", hr );
3442 hr = WsWriteEndElement( writer, NULL );
3443 ok( hr == S_OK, "got %08x\n", hr );
3444 check_output( writer, "<t>testtest</t>", __LINE__ );
3446 hr = set_output( writer );
3447 ok( hr == S_OK, "got %08x\n", hr );
3449 /* attribute */
3450 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3451 ok( hr == S_OK, "got %08x\n", hr );
3453 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3454 ok( hr == S_OK, "got %08x\n", hr );
3456 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3457 ok( hr == S_OK, "got %08x\n", hr );
3459 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3460 ok( hr == S_OK, "got %08x\n", hr );
3462 hr = WsWriteEndAttribute( writer, NULL );
3463 ok( hr == S_OK, "got %08x\n", hr );
3465 hr = WsWriteEndElement( writer, NULL );
3466 ok( hr == S_OK, "got %08x\n", hr );
3467 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3469 WsFreeWriter( writer );
3472 static void check_output_bin( WS_XML_WRITER *writer, const char *expected, int len, unsigned int line )
3474 WS_BYTES bytes;
3475 ULONG size = sizeof(bytes);
3476 HRESULT hr;
3478 memset( &bytes, 0, sizeof(bytes) );
3479 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
3480 ok( hr == S_OK, "%u: got %08x\n", line, hr );
3481 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
3482 if (bytes.length != len) return;
3483 ok( !memcmp( bytes.bytes, expected, bytes.length ), "%u: got %s expected %s\n", line,
3484 debugstr_bytes(bytes.bytes, bytes.length), debugstr_bytes((const BYTE *)expected, len) );
3487 static void test_binary_encoding(void)
3489 static const char res[] =
3490 {0x40,0x01,'t',0x01};
3491 static const char res2[] =
3492 {0x6d,0x01,'t',0x09,0x01,'p',0x02,'n','s',0x01};
3493 static const char res3[] =
3494 {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x01};
3495 static const char res4[] =
3496 {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x99,0x04,'t','e','s','t'};
3497 static const char res100[] =
3498 {0x40,0x01,'t',0x04,0x01,'t',0x98,0x00,0x01};
3499 static const char res101[] =
3500 {0x40,0x01,'t',0x35,0x01,'t',0x98,0x00,0x09,0x01,'p',0x02,'n','s',0x01};
3501 static const char res102[] =
3502 {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x00,0x09,0x02,'p','2',0x02,'n','s',0x01};
3503 static const char res103[] =
3504 {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x04,'t','e','s','t',0x09,0x02,'p','2',0x02,'n','s',0x01};
3505 static const char res200[] =
3506 {0x02,0x07,'c','o','m','m','e','n','t'};
3507 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
3508 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
3509 static const char prefix[] = "p", prefix2[] = "p2";
3510 static const char localname[] = "t", ns[] = "ns";
3511 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3512 WS_XML_STRING str, str2, str3, localname2 = {1, (BYTE *)"t"}, empty = {0, NULL};
3513 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
3514 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
3515 WS_XML_WRITER *writer;
3516 HRESULT hr;
3517 ULONG i;
3518 static const struct
3520 const char *prefix;
3521 const char *localname;
3522 const char *ns;
3523 const char *text;
3524 const char *result;
3525 int len_result;
3527 elem_tests[] =
3529 { NULL, localname, "", NULL, res, sizeof(res) }, /* short element */
3530 { prefix, localname, ns, NULL, res2, sizeof(res2) }, /* one character prefix element */
3531 { prefix2, localname, ns, NULL, res3, sizeof(res3) }, /* element */
3532 { prefix2, localname, ns, "test", res4, sizeof(res4) }, /* element with text */
3534 static const struct
3536 const char *prefix;
3537 const char *localname;
3538 const char *ns;
3539 const char *value;
3540 const char *result;
3541 int len_result;
3543 attr_tests[] =
3545 { NULL, localname, "", NULL, res100, sizeof(res100) }, /* short attribute */
3546 { prefix, localname, ns, NULL, res101, sizeof(res101) }, /* one character prefix attribute */
3547 { prefix2, localname, ns, NULL, res102, sizeof(res102) }, /* attribute */
3548 { prefix2, localname, ns, "test", res103, sizeof(res103) }, /* attribute with value */
3551 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3552 ok( hr == S_OK, "got %08x\n", hr );
3554 for (i = 0; i < ARRAY_SIZE( elem_tests ); i++)
3556 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3557 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3559 prefix_ptr = init_xmlstring( elem_tests[i].prefix, &str );
3560 localname_ptr = init_xmlstring( elem_tests[i].localname, &str2 );
3561 ns_ptr = init_xmlstring( elem_tests[i].ns, &str3 );
3563 hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3564 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3565 if (elem_tests[i].text)
3567 utf8.value.length = strlen( elem_tests[i].text );
3568 utf8.value.bytes = (BYTE *)elem_tests[i].text;
3569 hr = WsWriteText( writer, &utf8.text, NULL );
3570 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3572 hr = WsWriteEndElement( writer, NULL );
3573 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3574 if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
3577 for (i = 0; i < ARRAY_SIZE( attr_tests ); i++)
3579 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3580 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3582 prefix_ptr = init_xmlstring( attr_tests[i].prefix, &str );
3583 localname_ptr = init_xmlstring( attr_tests[i].localname, &str2 );
3584 ns_ptr = init_xmlstring( elem_tests[i].ns, &str3 );
3586 hr = WsWriteStartElement( writer, NULL, &localname2, &empty, NULL );
3587 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3588 hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
3589 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3590 if (attr_tests[i].value)
3592 utf8.value.length = strlen( attr_tests[i].value );
3593 utf8.value.bytes = (BYTE *)attr_tests[i].value;
3594 hr = WsWriteText( writer, &utf8.text, NULL );
3595 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3597 hr = WsWriteEndAttribute( writer, NULL );
3598 ok( hr == S_OK, "got %08x\n", hr );
3599 hr = WsWriteEndElement( writer, NULL );
3600 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3601 if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
3604 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3605 ok( hr == S_OK, "got %08x\n", hr );
3607 comment.value.bytes = (BYTE *)"comment";
3608 comment.value.length = sizeof("comment") - 1;
3609 hr = WsWriteNode( writer, &comment.node, NULL );
3610 ok( hr == S_OK, "got %08x\n", hr );
3611 if (hr == S_OK) check_output_bin( writer, res200, sizeof(res200), __LINE__ );
3613 WsFreeWriter( writer );
3616 static void test_namespaces(void)
3618 WS_XML_STRING prefix = {1, (BYTE *)"p"}, prefix2 = {1, (BYTE *)"q"};
3619 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"};
3620 WS_XML_STRING ns = {1, (BYTE *)"n"}, ns2 = {1, (BYTE *)"o"};
3621 WS_XML_WRITER *writer;
3622 HRESULT hr;
3624 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3625 ok( hr == S_OK, "got %08x\n", hr );
3627 hr = set_output( writer );
3628 ok( hr == S_OK, "got %08x\n", hr );
3629 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
3630 ok( hr == S_OK, "got %08x\n", hr );
3631 hr = WsWriteStartAttribute( writer, &prefix2, &localname2, &ns2, FALSE, NULL );
3632 ok( hr == S_OK, "got %08x\n", hr );
3633 hr = WsWriteEndAttribute( writer, NULL );
3634 ok( hr == S_OK, "got %08x\n", hr );
3635 hr = WsWriteEndElement( writer, NULL );
3636 ok( hr == S_OK, "got %08x\n", hr );
3637 check_output( writer, "<p:t q:a=\"\" xmlns:p=\"n\" xmlns:q=\"o\"/>", __LINE__ );
3639 WsFreeWriter( writer );
3642 static const WS_XML_STRING *init_xmlstring_dict( WS_XML_DICTIONARY *dict, ULONG id, WS_XML_STRING *str )
3644 if (id >= dict->stringCount) return NULL;
3645 str->length = dict->strings[id].length;
3646 str->bytes = dict->strings[id].bytes;
3647 str->dictionary = dict;
3648 str->id = id;
3649 return str;
3652 static HRESULT CALLBACK dict_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
3654 ULONG *call_count = state;
3656 (*call_count)++;
3657 switch (str->bytes[0])
3659 case 't':
3660 *id = 1;
3661 *found = TRUE;
3662 break;
3664 case 'n':
3665 *id = 2;
3666 *found = TRUE;
3667 break;
3669 case 'z':
3670 *id = 3;
3671 *found = TRUE;
3672 break;
3674 case 'v':
3675 *found = FALSE;
3676 return WS_E_OTHER;
3678 default:
3679 *found = FALSE;
3680 break;
3682 return S_OK;
3685 static void test_dictionary(void)
3687 static const char res[] =
3688 {0x42,0x04,0x01};
3689 static const char res2[] =
3690 {0x42,0x06,0x01};
3691 static const char res3[] =
3692 {0x53,0x06,0x0b,0x01,'p',0x0a,0x01};
3693 static const char res4[] =
3694 {0x43,0x02,'p','2',0x06,0x0b,0x02,'p','2',0x0a,0x01};
3695 static const char res5[] =
3696 {0x42,0x03,0x0a,0x05,0x01};
3697 static const char res6[] =
3698 {0x40,0x01,0x75,0x0a,0x05,0x01};
3699 static const char res7[] =
3700 {0x40,0x01,0x76,0x0a,0x05,0x01};
3701 static const char res8[] =
3702 {0x42,0x03,0x0a,0x05,0x01};
3703 static const char res9[] =
3704 {0x42,0x07,0x0a,0x05,0x01};
3705 static const char res10[] =
3706 {0x42,0xd6,0x03,0x0a,0x05,0x01};
3707 static const char res100[] =
3708 {0x42,0x06,0x06,0x06,0x98,0x00,0x01};
3709 static const char res101[] =
3710 {0x42,0x06,0x1b,0x06,0x98,0x00,0x0b,0x01,'p',0x0a,0x01};
3711 static const char res102[] =
3712 {0x42,0x06,0x07,0x02,'p','2',0x06,0x98,0x00,0x0b,0x02,'p','2',0x0a,0x01};
3713 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
3714 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
3715 WS_XML_STRING prefix, localname, ns, strings[6];
3716 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3717 WS_XML_DICTIONARY dict, *dict_builtin;
3718 WS_XML_WRITER *writer;
3719 HRESULT hr;
3720 ULONG i, call_count;
3721 static const struct
3723 ULONG prefix;
3724 ULONG localname;
3725 ULONG ns;
3726 const char *result;
3727 int len_result;
3729 elem_tests[] =
3731 { ~0u, 2, 0, res, sizeof(res) }, /* short dictionary element, invalid dict id */
3732 { ~0u, 3, 0, res2, sizeof(res2) }, /* short dictionary element */
3733 { 1, 3, 5, res3, sizeof(res3) }, /* single character prefix dictionary element */
3734 { 4, 3, 5, res4, sizeof(res4) }, /* dictionary element */
3736 static const struct
3738 ULONG prefix;
3739 ULONG localname;
3740 ULONG ns;
3741 const char *result;
3742 int len_result;
3744 attr_tests[] =
3746 { ~0u, 3, 0, res100, sizeof(res100) }, /* short dictionary attribute */
3747 { 1, 3, 5, res101, sizeof(res101) }, /* single character prefix dictionary attribute */
3748 { 4, 3, 5, res102, sizeof(res102) }, /* dictionary attribute */
3751 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3752 ok( hr == S_OK, "got %08x\n", hr );
3754 strings[0].length = 0;
3755 strings[0].bytes = NULL;
3756 strings[0].dictionary = &dict;
3757 strings[0].id = 0;
3758 strings[1].length = 1;
3759 strings[1].bytes = (BYTE *)"p";
3760 strings[1].dictionary = &dict;
3761 strings[1].id = 1;
3762 strings[2].length = 1;
3763 strings[2].bytes = (BYTE *)"t";
3764 strings[2].dictionary = &dict;
3765 strings[2].id = ~0u;
3766 strings[3].length = 1;
3767 strings[3].bytes = (BYTE *)"u";
3768 strings[3].dictionary = &dict;
3769 strings[3].id = 3;
3770 strings[4].length = 2;
3771 strings[4].bytes = (BYTE *)"p2";
3772 strings[4].dictionary = &dict;
3773 strings[4].id = 4;
3774 strings[5].length = 2;
3775 strings[5].bytes = (BYTE *)"ns";
3776 strings[5].dictionary = &dict;
3777 strings[5].id = 5;
3779 UuidCreate( &dict.guid );
3780 dict.strings = strings;
3781 dict.stringCount = ARRAY_SIZE( strings );
3782 dict.isConst = TRUE;
3784 bin.staticDictionary = &dict;
3786 for (i = 0; i < ARRAY_SIZE( elem_tests ); i++)
3788 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3789 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3791 prefix_ptr = init_xmlstring_dict( &dict, elem_tests[i].prefix, &prefix );
3792 localname_ptr = init_xmlstring_dict( &dict, elem_tests[i].localname, &localname );
3793 ns_ptr = init_xmlstring_dict( &dict, elem_tests[i].ns, &ns );
3795 hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3796 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3797 hr = WsWriteEndElement( writer, NULL );
3798 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3799 if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
3802 for (i = 0; i < ARRAY_SIZE( attr_tests ); i++)
3804 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3805 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3807 prefix_ptr = init_xmlstring_dict( &dict, attr_tests[i].prefix, &prefix );
3808 localname_ptr = init_xmlstring_dict( &dict, attr_tests[i].localname, &localname );
3809 ns_ptr = init_xmlstring_dict( &dict, attr_tests[i].ns, &ns );
3811 hr = WsWriteStartElement( writer, NULL, &strings[3], &strings[0], NULL );
3812 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3813 hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
3814 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3815 hr = WsWriteEndAttribute( writer, NULL );
3816 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3817 hr = WsWriteEndElement( writer, NULL );
3818 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3819 if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
3822 /* callback */
3823 bin.staticDictionary = NULL;
3824 bin.dynamicStringCallback = dict_cb;
3825 bin.dynamicStringCallbackState = &call_count;
3827 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3828 ok( hr == S_OK, "got %08x\n", hr );
3829 init_xmlstring( "t", &localname );
3830 init_xmlstring( "ns", &ns );
3831 call_count = 0;
3832 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3833 ok( hr == S_OK, "got %08x\n", hr );
3834 hr = WsWriteEndElement( writer, NULL );
3835 ok( hr == S_OK, "got %08x\n", hr );
3836 ok( call_count == 2, "got %u\n", call_count );
3837 check_output_bin( writer, res5, sizeof(res5), __LINE__ );
3839 /* unknown string */
3840 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3841 ok( hr == S_OK, "got %08x\n", hr );
3842 init_xmlstring( "u", &localname );
3843 init_xmlstring( "ns", &ns );
3844 call_count = 0;
3845 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3846 ok( hr == S_OK, "got %08x\n", hr );
3847 hr = WsWriteEndElement( writer, NULL );
3848 ok( hr == S_OK, "got %08x\n", hr );
3849 ok( call_count == 2, "got %u\n", call_count );
3850 check_output_bin( writer, res6, sizeof(res6), __LINE__ );
3852 /* unknown string, error return from callback */
3853 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3854 ok( hr == S_OK, "got %08x\n", hr );
3855 init_xmlstring( "v", &localname );
3856 init_xmlstring( "ns", &ns );
3857 call_count = 0;
3858 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3859 ok( hr == S_OK, "got %08x\n", hr );
3860 hr = WsWriteEndElement( writer, NULL );
3861 ok( hr == S_OK, "got %08x\n", hr );
3862 ok( call_count == 2, "got %u\n", call_count );
3863 check_output_bin( writer, res7, sizeof(res7), __LINE__ );
3865 /* dictionary and callback */
3866 hr = WsGetDictionary( WS_ENCODING_XML_BINARY_1, &dict_builtin, NULL );
3867 ok( hr == S_OK, "got %08x\n", hr );
3868 bin.staticDictionary = dict_builtin;
3870 /* string in dictionary, no string dictionary set */
3871 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3872 ok( hr == S_OK, "got %08x\n", hr );
3873 init_xmlstring( "t", &localname );
3874 init_xmlstring( "ns", &ns );
3875 call_count = 0;
3876 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3877 ok( hr == S_OK, "got %08x\n", hr );
3878 hr = WsWriteEndElement( writer, NULL );
3879 ok( hr == S_OK, "got %08x\n", hr );
3880 ok( call_count == 2, "got %u\n", call_count );
3881 check_output_bin( writer, res8, sizeof(res8), __LINE__ );
3883 /* string not in dictionary, no string dictionary set */
3884 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3885 ok( hr == S_OK, "got %08x\n", hr );
3886 init_xmlstring( "z", &localname );
3887 init_xmlstring( "ns", &ns );
3888 call_count = 0;
3889 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3890 ok( hr == S_OK, "got %08x\n", hr );
3891 hr = WsWriteEndElement( writer, NULL );
3892 ok( hr == S_OK, "got %08x\n", hr );
3893 ok( call_count == 2, "got %u\n", call_count );
3894 check_output_bin( writer, res9, sizeof(res9), __LINE__ );
3896 /* string in dictionary, string dictionary set */
3897 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3898 ok( hr == S_OK, "got %08x\n", hr );
3899 init_xmlstring_dict( dict_builtin, 235, &localname );
3900 init_xmlstring( "ns", &ns );
3901 call_count = 0;
3902 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3903 ok( hr == S_OK, "got %08x\n", hr );
3904 hr = WsWriteEndElement( writer, NULL );
3905 ok( hr == S_OK, "got %08x\n", hr );
3906 ok( call_count == 1, "got %u\n", call_count );
3907 check_output_bin( writer, res10, sizeof(res10), __LINE__ );
3909 WsFreeWriter( writer );
3912 static void test_union_type(void)
3914 static const WCHAR testW[] = {'t','e','s','t',0};
3915 static WS_XML_STRING str_ns = {0, NULL}, str_a = {1, (BYTE *)"a"}, str_b = {1, (BYTE *)"b"};
3916 static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"};
3917 HRESULT hr;
3918 WS_XML_WRITER *writer;
3919 WS_UNION_DESCRIPTION u;
3920 WS_UNION_FIELD_DESCRIPTION f, f2, *fields[2];
3921 WS_FIELD_DESCRIPTION f_struct, *fields_struct[1];
3922 WS_STRUCT_DESCRIPTION s;
3923 enum choice {CHOICE_A, CHOICE_B, CHOICE_NONE};
3924 struct test
3926 enum choice choice;
3927 union
3929 const WCHAR *a;
3930 UINT32 b;
3931 } value;
3932 } test;
3934 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3935 ok( hr == S_OK, "got %08x\n", hr );
3937 memset( &f, 0, sizeof(f) );
3938 f.value = CHOICE_A;
3939 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
3940 f.field.localName = &str_a;
3941 f.field.ns = &str_ns;
3942 f.field.type = WS_WSZ_TYPE;
3943 f.field.offset = FIELD_OFFSET(struct test, value.a);
3944 fields[0] = &f;
3946 memset( &f2, 0, sizeof(f2) );
3947 f2.value = CHOICE_B;
3948 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
3949 f2.field.localName = &str_b;
3950 f2.field.ns = &str_ns;
3951 f2.field.type = WS_UINT32_TYPE;
3952 f2.field.offset = FIELD_OFFSET(struct test, value.b);
3953 fields[1] = &f2;
3955 memset( &u, 0, sizeof(u) );
3956 u.size = sizeof(struct test);
3957 u.alignment = TYPE_ALIGNMENT(struct test);
3958 u.fields = fields;
3959 u.fieldCount = 2;
3960 u.enumOffset = FIELD_OFFSET(struct test, choice);
3961 u.noneEnumValue = CHOICE_NONE;
3963 memset( &f_struct, 0, sizeof(f_struct) );
3964 f_struct.mapping = WS_ELEMENT_CHOICE_FIELD_MAPPING;
3965 f_struct.type = WS_UNION_TYPE;
3966 f_struct.typeDescription = &u;
3967 fields_struct[0] = &f_struct;
3969 memset( &s, 0, sizeof(s) );
3970 s.size = sizeof(struct test);
3971 s.alignment = TYPE_ALIGNMENT(struct test);
3972 s.fields = fields_struct;
3973 s.fieldCount = 1;
3974 s.typeLocalName = &str_s;
3975 s.typeNs = &str_ns;
3977 hr = set_output( writer );
3978 ok( hr == S_OK, "got %08x\n", hr );
3979 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
3980 ok( hr == S_OK, "got %08x\n", hr );
3981 test.choice = CHOICE_A;
3982 test.value.a = testW;
3983 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3984 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
3985 ok( hr == S_OK, "got %08x\n", hr );
3986 hr = WsWriteEndElement( writer, NULL );
3987 ok( hr == S_OK, "got %08x\n", hr );
3988 check_output( writer, "<t><a>test</a></t>", __LINE__ );
3990 hr = set_output( writer );
3991 ok( hr == S_OK, "got %08x\n", hr );
3992 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
3993 ok( hr == S_OK, "got %08x\n", hr );
3994 test.choice = CHOICE_B;
3995 test.value.b = 123;
3996 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3997 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
3998 ok( hr == S_OK, "got %08x\n", hr );
3999 hr = WsWriteEndElement( writer, NULL );
4000 ok( hr == S_OK, "got %08x\n", hr );
4001 check_output( writer, "<t><b>123</b></t>", __LINE__ );
4003 hr = set_output( writer );
4004 ok( hr == S_OK, "got %08x\n", hr );
4005 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4006 ok( hr == S_OK, "got %08x\n", hr );
4007 test.choice = CHOICE_NONE;
4008 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4009 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4010 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
4012 hr = set_output( writer );
4013 ok( hr == S_OK, "got %08x\n", hr );
4014 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4015 ok( hr == S_OK, "got %08x\n", hr );
4016 test.choice = CHOICE_NONE;
4017 f_struct.options = WS_FIELD_OPTIONAL;
4018 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4019 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4020 ok( hr == S_OK, "got %08x\n", hr );
4021 hr = WsWriteEndElement( writer, NULL );
4022 ok( hr == S_OK, "got %08x\n", hr );
4023 check_output( writer, "<t/>", __LINE__ );
4025 WsFreeWriter( writer );
4028 static void prepare_binary_type_test( WS_XML_WRITER *writer, const WS_XML_STRING *prefix,
4029 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4031 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
4032 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
4033 HRESULT hr;
4035 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
4036 ok( hr == S_OK, "got %08x\n", hr );
4037 hr = WsWriteStartElement( writer, prefix, localname, ns, NULL );
4038 ok( hr == S_OK, "got %08x\n", hr );
4041 static void test_text_types_binary(void)
4043 static WCHAR testW[] = {'t','e','s','t'};
4044 static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"}, str_u = {1, (BYTE *)"u"};
4045 static WS_XML_STRING str_ns = {0, NULL};
4046 static const char res[] =
4047 {0x40,0x01,'t',0x40,0x01,'u',0x99,0x04,'t','e','s','t',0x01};
4048 static const char res2[] =
4049 {0x40,0x01,'t',0x40,0x01,'u',0x9e,0x03,'t','e','s',0x9f,0x01,'t',0x01};
4050 static const char res2a[] =
4051 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x03,'t','e','s',0x01};
4052 static const char res2b[] =
4053 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x01,'t',0x01};
4054 static const char res2c[] =
4055 {0x40,0x01,'t',0x40,0x01,'u',0x01,0x01};
4056 static const char res2d[] =
4057 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0xff,'a','a','a','a','a','a','a','a','a','a',
4058 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4059 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4060 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4061 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4062 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4063 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4064 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4065 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4066 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4067 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4068 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4069 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4070 'a','a','a','a','a',0x01};
4071 static const char res2e[] =
4072 {0x40,0x01,'t',0x40,0x01,'u',0x9e,0xff,'a','a','a','a','a','a','a','a','a','a',
4073 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4074 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4075 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4076 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4077 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4078 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4079 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4080 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4081 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4082 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4083 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4084 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4085 'a','a','a','a','a',0x9f,0x01,'a',0x01};
4086 static const char res2f[] =
4087 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x06,'t','e','s','t','t','e',0x01};
4088 static const char res3[] =
4089 {0x40,0x01,'t',0x40,0x01,'u',0x87,0x01};
4090 static const char res4[] =
4091 {0x40,0x01,'t',0x40,0x01,'u',0x89,0xff,0x01};
4092 static const char res5[] =
4093 {0x40,0x01,'t',0x40,0x01,'u',0x83,0x01};
4094 static const char res5b[] =
4095 {0x40,0x01,'t',0x40,0x01,'u',0x89,0x02,0x01};
4096 static const char res6[] =
4097 {0x40,0x01,'t',0x40,0x01,'u',0x81,0x01};
4098 static const char res7[] =
4099 {0x40,0x01,'t',0x40,0x01,'u',0x89,0x02,0x01};
4100 static const char res8[] =
4101 {0x40,0x01,'t',0x40,0x01,'u',0x93,0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x40,0x01};
4102 static const char res8a[] =
4103 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x7f,0x01};
4104 static const char res8b[] =
4105 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x01};
4106 static const char res8c[] =
4107 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x7f,0x01};
4108 static const char res9[] =
4109 {0x40,0x01,'t',0x40,0x01,'u',0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4110 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4111 static const char res10[] =
4112 {0x40,0x01,'t',0x40,0x01,'u',0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4113 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4114 static const char res11[] =
4115 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01};
4116 static const char res11b[] =
4117 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01};
4118 static const char res11c[] =
4119 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4120 static const char res11d[] =
4121 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01};
4122 HRESULT hr;
4123 WS_XML_WRITER *writer;
4124 WS_UNION_DESCRIPTION u;
4125 WS_UNION_FIELD_DESCRIPTION f, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, *fields[11];
4126 WS_FIELD_DESCRIPTION f_struct, *fields_struct[1];
4127 WS_STRUCT_DESCRIPTION s;
4128 struct test
4130 WS_XML_TEXT_TYPE type;
4131 union
4133 WS_XML_STRING val_utf8;
4134 WS_STRING val_utf16;
4135 WS_BYTES val_bytes;
4136 BOOL val_bool;
4137 INT32 val_int32;
4138 INT64 val_int64;
4139 UINT64 val_uint64;
4140 double val_double;
4141 GUID val_guid;
4142 WS_UNIQUE_ID val_unique_id;
4143 WS_DATETIME val_datetime;
4144 } u;
4145 } test;
4146 BYTE buf[256];
4148 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4149 ok( hr == S_OK, "got %08x\n", hr );
4151 memset( &f, 0, sizeof(f) );
4152 f.value = WS_XML_TEXT_TYPE_UTF8;
4153 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4154 f.field.localName = &str_u;
4155 f.field.ns = &str_ns;
4156 f.field.type = WS_XML_STRING_TYPE;
4157 f.field.offset = FIELD_OFFSET(struct test, u.val_utf8);
4158 fields[0] = &f;
4160 memset( &f2, 0, sizeof(f2) );
4161 f2.value = WS_XML_TEXT_TYPE_UTF16;
4162 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4163 f2.field.localName = &str_u;
4164 f2.field.ns = &str_ns;
4165 f2.field.type = WS_STRING_TYPE;
4166 f2.field.offset = FIELD_OFFSET(struct test, u.val_utf16);
4167 fields[1] = &f2;
4169 memset( &f3, 0, sizeof(f3) );
4170 f3.value = WS_XML_TEXT_TYPE_BASE64;
4171 f3.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4172 f3.field.localName = &str_u;
4173 f3.field.ns = &str_ns;
4174 f3.field.type = WS_BYTES_TYPE;
4175 f3.field.offset = FIELD_OFFSET(struct test, u.val_bytes);
4176 fields[2] = &f3;
4178 memset( &f4, 0, sizeof(f4) );
4179 f4.value = WS_XML_TEXT_TYPE_BOOL;
4180 f4.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4181 f4.field.localName = &str_u;
4182 f4.field.ns = &str_ns;
4183 f4.field.type = WS_BOOL_TYPE;
4184 f4.field.offset = FIELD_OFFSET(struct test, u.val_bool);
4185 fields[3] = &f4;
4187 memset( &f5, 0, sizeof(f5) );
4188 f5.value = WS_XML_TEXT_TYPE_INT32;
4189 f5.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4190 f5.field.localName = &str_u;
4191 f5.field.ns = &str_ns;
4192 f5.field.type = WS_INT32_TYPE;
4193 f5.field.offset = FIELD_OFFSET(struct test, u.val_int32);
4194 fields[4] = &f5;
4196 memset( &f6, 0, sizeof(f6) );
4197 f6.value = WS_XML_TEXT_TYPE_INT64;
4198 f6.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4199 f6.field.localName = &str_u;
4200 f6.field.ns = &str_ns;
4201 f6.field.type = WS_INT64_TYPE;
4202 f6.field.offset = FIELD_OFFSET(struct test, u.val_int64);
4203 fields[5] = &f6;
4205 memset( &f7, 0, sizeof(f7) );
4206 f7.value = WS_XML_TEXT_TYPE_UINT64;
4207 f7.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4208 f7.field.localName = &str_u;
4209 f7.field.ns = &str_ns;
4210 f7.field.type = WS_UINT64_TYPE;
4211 f7.field.offset = FIELD_OFFSET(struct test, u.val_uint64);
4212 fields[6] = &f7;
4214 memset( &f8, 0, sizeof(f8) );
4215 f8.value = WS_XML_TEXT_TYPE_DOUBLE;
4216 f8.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4217 f8.field.localName = &str_u;
4218 f8.field.ns = &str_ns;
4219 f8.field.type = WS_DOUBLE_TYPE;
4220 f8.field.offset = FIELD_OFFSET(struct test, u.val_double);
4221 fields[7] = &f8;
4223 memset( &f9, 0, sizeof(f9) );
4224 f9.value = WS_XML_TEXT_TYPE_GUID;
4225 f9.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4226 f9.field.localName = &str_u;
4227 f9.field.ns = &str_ns;
4228 f9.field.type = WS_GUID_TYPE;
4229 f9.field.offset = FIELD_OFFSET(struct test, u.val_guid);
4230 fields[8] = &f9;
4232 memset( &f10, 0, sizeof(f10) );
4233 f10.value = WS_XML_TEXT_TYPE_UNIQUE_ID;
4234 f10.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4235 f10.field.localName = &str_u;
4236 f10.field.ns = &str_ns;
4237 f10.field.type = WS_UNIQUE_ID_TYPE;
4238 f10.field.offset = FIELD_OFFSET(struct test, u.val_unique_id);
4239 fields[9] = &f10;
4241 memset( &f11, 0, sizeof(f11) );
4242 f11.value = WS_XML_TEXT_TYPE_DATETIME;
4243 f11.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4244 f11.field.localName = &str_u;
4245 f11.field.ns = &str_ns;
4246 f11.field.type = WS_DATETIME_TYPE;
4247 f11.field.offset = FIELD_OFFSET(struct test, u.val_datetime);
4248 fields[10] = &f11;
4250 memset( &u, 0, sizeof(u) );
4251 u.size = sizeof(struct test);
4252 u.alignment = TYPE_ALIGNMENT(struct test);
4253 u.fields = fields;
4254 u.fieldCount = 11;
4255 u.enumOffset = FIELD_OFFSET(struct test, type);
4257 memset( &f_struct, 0, sizeof(f_struct) );
4258 f_struct.mapping = WS_ELEMENT_CHOICE_FIELD_MAPPING;
4259 f_struct.type = WS_UNION_TYPE;
4260 f_struct.typeDescription = &u;
4261 fields_struct[0] = &f_struct;
4263 memset( &s, 0, sizeof(s) );
4264 s.size = sizeof(struct test);
4265 s.alignment = TYPE_ALIGNMENT(struct test);
4266 s.fields = fields_struct;
4267 s.fieldCount = 1;
4268 s.typeLocalName = &str_s;
4269 s.typeNs = &str_ns;
4271 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4272 test.type = WS_XML_TEXT_TYPE_UTF8;
4273 test.u.val_utf8.bytes = (BYTE *)"test";
4274 test.u.val_utf8.length = 4;
4275 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4276 &test, sizeof(test), NULL );
4277 ok( hr == S_OK, "got %08x\n", hr );
4278 hr = WsWriteEndElement( writer, NULL );
4279 ok( hr == S_OK, "got %08x\n", hr );
4280 check_output_bin( writer, res, sizeof(res), __LINE__ );
4282 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4283 test.type = WS_XML_TEXT_TYPE_UTF16;
4284 test.u.val_utf16.chars = testW;
4285 test.u.val_utf16.length = 4;
4286 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4287 &test, sizeof(test), NULL );
4288 ok( hr == S_OK, "got %08x\n", hr );
4289 hr = WsWriteEndElement( writer, NULL );
4290 ok( hr == S_OK, "got %08x\n", hr );
4291 check_output_bin( writer, res, sizeof(res), __LINE__ );
4293 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4294 test.type = WS_XML_TEXT_TYPE_BASE64;
4295 test.u.val_bytes.bytes = (BYTE *)"test";
4296 test.u.val_bytes.length = 4;
4297 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4298 &test, sizeof(test), NULL );
4299 ok( hr == S_OK, "got %08x\n", hr );
4300 hr = WsWriteEndElement( writer, NULL );
4301 ok( hr == S_OK, "got %08x\n", hr );
4302 check_output_bin( writer, res2, sizeof(res2), __LINE__ );
4304 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4305 test.type = WS_XML_TEXT_TYPE_BASE64;
4306 test.u.val_bytes.bytes = (BYTE *)"tes";
4307 test.u.val_bytes.length = 3;
4308 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4309 &test, sizeof(test), NULL );
4310 ok( hr == S_OK, "got %08x\n", hr );
4311 hr = WsWriteEndElement( writer, NULL );
4312 ok( hr == S_OK, "got %08x\n", hr );
4313 check_output_bin( writer, res2a, sizeof(res2a), __LINE__ );
4315 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4316 test.type = WS_XML_TEXT_TYPE_BASE64;
4317 test.u.val_bytes.bytes = (BYTE *)"t";
4318 test.u.val_bytes.length = 1;
4319 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4320 &test, sizeof(test), NULL );
4321 ok( hr == S_OK, "got %08x\n", hr );
4322 hr = WsWriteEndElement( writer, NULL );
4323 ok( hr == S_OK, "got %08x\n", hr );
4324 check_output_bin( writer, res2b, sizeof(res2b), __LINE__ );
4326 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4327 test.type = WS_XML_TEXT_TYPE_BASE64;
4328 test.u.val_bytes.bytes = (BYTE *)"";
4329 test.u.val_bytes.length = 0;
4330 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4331 &test, sizeof(test), NULL );
4332 ok( hr == S_OK, "got %08x\n", hr );
4333 hr = WsWriteEndElement( writer, NULL );
4334 ok( hr == S_OK, "got %08x\n", hr );
4335 check_output_bin( writer, res2c, sizeof(res2c), __LINE__ );
4337 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4338 memset( buf, 'a', sizeof(buf) );
4339 test.type = WS_XML_TEXT_TYPE_BASE64;
4340 test.u.val_bytes.bytes = buf;
4341 test.u.val_bytes.length = 255;
4342 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4343 &test, sizeof(test), NULL );
4344 ok( hr == S_OK, "got %08x\n", hr );
4345 hr = WsWriteEndElement( writer, NULL );
4346 ok( hr == S_OK, "got %08x\n", hr );
4347 check_output_bin( writer, res2d, sizeof(res2d), __LINE__ );
4349 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4350 test.type = WS_XML_TEXT_TYPE_BASE64;
4351 test.u.val_bytes.bytes = buf;
4352 test.u.val_bytes.length = 256;
4353 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4354 &test, sizeof(test), NULL );
4355 ok( hr == S_OK, "got %08x\n", hr );
4356 hr = WsWriteEndElement( writer, NULL );
4357 ok( hr == S_OK, "got %08x\n", hr );
4358 check_output_bin( writer, res2e, sizeof(res2e), __LINE__ );
4360 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4361 test.type = WS_XML_TEXT_TYPE_BASE64;
4362 test.u.val_bytes.bytes = (BYTE *)"testte";
4363 test.u.val_bytes.length = 6;
4364 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4365 &test, sizeof(test), NULL );
4366 ok( hr == S_OK, "got %08x\n", hr );
4367 hr = WsWriteEndElement( writer, NULL );
4368 ok( hr == S_OK, "got %08x\n", hr );
4369 check_output_bin( writer, res2f, sizeof(res2f), __LINE__ );
4371 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4372 test.type = WS_XML_TEXT_TYPE_BOOL;
4373 test.u.val_bool = TRUE;
4374 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4375 &test, sizeof(test), NULL );
4376 ok( hr == S_OK, "got %08x\n", hr );
4377 hr = WsWriteEndElement( writer, NULL );
4378 ok( hr == S_OK, "got %08x\n", hr );
4379 check_output_bin( writer, res3, sizeof(res3), __LINE__ );
4381 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4382 test.type = WS_XML_TEXT_TYPE_INT32;
4383 test.u.val_int32 = -1;
4384 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4385 &test, sizeof(test), NULL );
4386 ok( hr == S_OK, "got %08x\n", hr );
4387 hr = WsWriteEndElement( writer, NULL );
4388 ok( hr == S_OK, "got %08x\n", hr );
4389 check_output_bin( writer, res4, sizeof(res4), __LINE__ );
4391 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4392 test.type = WS_XML_TEXT_TYPE_INT64;
4393 test.u.val_int64 = -1;
4394 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4395 &test, sizeof(test), NULL );
4396 ok( hr == S_OK, "got %08x\n", hr );
4397 hr = WsWriteEndElement( writer, NULL );
4398 ok( hr == S_OK, "got %08x\n", hr );
4399 check_output_bin( writer, res4, sizeof(res4), __LINE__ );
4401 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4402 test.type = WS_XML_TEXT_TYPE_UINT64;
4403 test.u.val_uint64 = 1;
4404 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4405 &test, sizeof(test), NULL );
4406 ok( hr == S_OK, "got %08x\n", hr );
4407 hr = WsWriteEndElement( writer, NULL );
4408 ok( hr == S_OK, "got %08x\n", hr );
4409 check_output_bin( writer, res5, sizeof(res5), __LINE__ );
4411 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4412 test.type = WS_XML_TEXT_TYPE_UINT64;
4413 test.u.val_uint64 = 2;
4414 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4415 &test, sizeof(test), NULL );
4416 ok( hr == S_OK, "got %08x\n", hr );
4417 hr = WsWriteEndElement( writer, NULL );
4418 ok( hr == S_OK, "got %08x\n", hr );
4419 check_output_bin( writer, res5b, sizeof(res5b), __LINE__ );
4421 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4422 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4423 test.u.val_double = 0.0;
4424 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4425 &test, sizeof(test), NULL );
4426 ok( hr == S_OK, "got %08x\n", hr );
4427 hr = WsWriteEndElement( writer, NULL );
4428 ok( hr == S_OK, "got %08x\n", hr );
4429 check_output_bin( writer, res6, sizeof(res6), __LINE__ );
4431 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4432 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4433 test.u.val_double = 2.0;
4434 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4435 &test, sizeof(test), NULL );
4436 ok( hr == S_OK, "got %08x\n", hr );
4437 hr = WsWriteEndElement( writer, NULL );
4438 ok( hr == S_OK, "got %08x\n", hr );
4439 check_output_bin( writer, res7, sizeof(res7), __LINE__ );
4441 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4442 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4443 test.u.val_double = 2.1;
4444 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4445 &test, sizeof(test), NULL );
4446 ok( hr == S_OK, "got %08x\n", hr );
4447 hr = WsWriteEndElement( writer, NULL );
4448 ok( hr == S_OK, "got %08x\n", hr );
4449 check_output_bin( writer, res8, sizeof(res8), __LINE__ );
4451 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4452 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4453 test.u.val_double = INFINITY;
4454 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4455 &test, sizeof(test), NULL );
4456 ok( hr == S_OK, "got %08x\n", hr );
4457 hr = WsWriteEndElement( writer, NULL );
4458 ok( hr == S_OK, "got %08x\n", hr );
4459 check_output_bin( writer, res8a, sizeof(res8a), __LINE__ );
4461 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4462 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4463 test.u.val_double = -INFINITY;
4464 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4465 &test, sizeof(test), NULL );
4466 ok( hr == S_OK, "got %08x\n", hr );
4467 hr = WsWriteEndElement( writer, NULL );
4468 ok( hr == S_OK, "got %08x\n", hr );
4469 check_output_bin( writer, res8b, sizeof(res8b), __LINE__ );
4471 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4472 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4473 test.u.val_double = NAN;
4474 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4475 &test, sizeof(test), NULL );
4476 ok( hr == S_OK, "got %08x\n", hr );
4477 hr = WsWriteEndElement( writer, NULL );
4478 ok( hr == S_OK, "got %08x\n", hr );
4479 check_output_bin( writer, res8c, sizeof(res8c), __LINE__ );
4481 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4482 test.type = WS_XML_TEXT_TYPE_GUID;
4483 memset( &test.u.val_guid, 0, sizeof(test.u.val_guid) );
4484 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4485 &test, sizeof(test), NULL );
4486 ok( hr == S_OK, "got %08x\n", hr );
4487 hr = WsWriteEndElement( writer, NULL );
4488 ok( hr == S_OK, "got %08x\n", hr );
4489 check_output_bin( writer, res9, sizeof(res9), __LINE__ );
4491 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4492 test.type = WS_XML_TEXT_TYPE_UNIQUE_ID;
4493 memset( &test.u.val_unique_id, 0, sizeof(test.u.val_unique_id) );
4494 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4495 &test, sizeof(test), NULL );
4496 ok( hr == S_OK, "got %08x\n", hr );
4497 hr = WsWriteEndElement( writer, NULL );
4498 ok( hr == S_OK, "got %08x\n", hr );
4499 check_output_bin( writer, res10, sizeof(res10), __LINE__ );
4501 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4502 test.type = WS_XML_TEXT_TYPE_DATETIME;
4503 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4504 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4505 &test, sizeof(test), NULL );
4506 ok( hr == S_OK, "got %08x\n", hr );
4507 hr = WsWriteEndElement( writer, NULL );
4508 ok( hr == S_OK, "got %08x\n", hr );
4509 check_output_bin( writer, res11, sizeof(res11), __LINE__ );
4511 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4512 test.type = WS_XML_TEXT_TYPE_DATETIME;
4513 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4514 test.u.val_datetime.format = WS_DATETIME_FORMAT_LOCAL;
4515 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4516 &test, sizeof(test), NULL );
4517 ok( hr == S_OK, "got %08x\n", hr );
4518 hr = WsWriteEndElement( writer, NULL );
4519 ok( hr == S_OK, "got %08x\n", hr );
4520 check_output_bin( writer, res11b, sizeof(res11b), __LINE__ );
4522 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4523 test.type = WS_XML_TEXT_TYPE_DATETIME;
4524 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4525 test.u.val_datetime.format = WS_DATETIME_FORMAT_NONE;
4526 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4527 &test, sizeof(test), NULL );
4528 ok( hr == S_OK, "got %08x\n", hr );
4529 hr = WsWriteEndElement( writer, NULL );
4530 ok( hr == S_OK, "got %08x\n", hr );
4531 check_output_bin( writer, res11c, sizeof(res11c), __LINE__ );
4533 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4534 test.type = WS_XML_TEXT_TYPE_DATETIME;
4535 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4536 test.u.val_datetime.ticks = 1;
4537 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4538 &test, sizeof(test), NULL );
4539 ok( hr == S_OK, "got %08x\n", hr );
4540 hr = WsWriteEndElement( writer, NULL );
4541 ok( hr == S_OK, "got %08x\n", hr );
4542 check_output_bin( writer, res11d, sizeof(res11d), __LINE__ );
4544 WsFreeWriter( writer );
4547 static void test_repeating_element_choice(void)
4549 static const WCHAR testW[] = {'t','e','s','t',0};
4550 static WS_XML_STRING str_ns = {0, NULL}, str_a = {1, (BYTE *)"a"}, str_b = {1, (BYTE *)"b"};
4551 static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"};
4552 HRESULT hr;
4553 WS_XML_WRITER *writer;
4554 WS_UNION_DESCRIPTION u;
4555 WS_UNION_FIELD_DESCRIPTION f, f2, *fields[2];
4556 WS_FIELD_DESCRIPTION f_items, *fields_items[1];
4557 WS_STRUCT_DESCRIPTION s;
4558 enum choice {CHOICE_A, CHOICE_B, CHOICE_NONE};
4559 struct item
4561 enum choice choice;
4562 union
4564 const WCHAR *a;
4565 UINT32 b;
4566 } value;
4567 } items[2];
4568 struct test
4570 struct item *items;
4571 ULONG count;
4572 } test;
4574 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4575 ok( hr == S_OK, "got %08x\n", hr );
4577 memset( &f, 0, sizeof(f) );
4578 f.value = CHOICE_A;
4579 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4580 f.field.localName = &str_a;
4581 f.field.ns = &str_ns;
4582 f.field.type = WS_WSZ_TYPE;
4583 f.field.offset = FIELD_OFFSET(struct item, value.a);
4584 fields[0] = &f;
4586 memset( &f2, 0, sizeof(f2) );
4587 f2.value = CHOICE_B;
4588 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4589 f2.field.localName = &str_b;
4590 f2.field.ns = &str_ns;
4591 f2.field.type = WS_UINT32_TYPE;
4592 f2.field.offset = FIELD_OFFSET(struct item, value.b);
4593 fields[1] = &f2;
4595 memset( &u, 0, sizeof(u) );
4596 u.size = sizeof(struct item);
4597 u.alignment = TYPE_ALIGNMENT(struct item);
4598 u.fields = fields;
4599 u.fieldCount = 2;
4600 u.enumOffset = FIELD_OFFSET(struct item, choice);
4601 u.noneEnumValue = CHOICE_NONE;
4603 memset( &f_items, 0, sizeof(f_items) );
4604 f_items.mapping = WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING;
4605 f_items.localName = &str_t;
4606 f_items.ns = &str_ns;
4607 f_items.type = WS_UNION_TYPE;
4608 f_items.typeDescription = &u;
4609 f_items.countOffset = FIELD_OFFSET(struct test, count);
4610 fields_items[0] = &f_items;
4612 memset( &s, 0, sizeof(s) );
4613 s.size = sizeof(struct test);
4614 s.alignment = TYPE_ALIGNMENT(struct test);
4615 s.fields = fields_items;
4616 s.fieldCount = 1;
4617 s.typeLocalName = &str_s;
4618 s.typeNs = &str_ns;
4620 items[0].choice = CHOICE_A;
4621 items[0].value.a = testW;
4622 items[1].choice = CHOICE_B;
4623 items[1].value.b = 1;
4624 test.items = items;
4625 test.count = 2;
4627 hr = set_output( writer );
4628 ok( hr == S_OK, "got %08x\n", hr );
4629 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4630 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4631 ok( hr == S_OK, "got %08x\n", hr );
4632 check_output( writer, "<t><a>test</a><b>1</b></t>", __LINE__ );
4634 items[0].choice = CHOICE_NONE;
4635 hr = set_output( writer );
4636 ok( hr == S_OK, "got %08x\n", hr );
4637 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4638 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4639 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
4641 test.count = 0;
4642 hr = set_output( writer );
4643 ok( hr == S_OK, "got %08x\n", hr );
4644 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4645 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4646 ok( hr == S_OK, "got %08x\n", hr );
4647 check_output( writer, "<t/>", __LINE__ );
4649 WsFreeWriter( writer );
4652 START_TEST(writer)
4654 test_WsCreateWriter();
4655 test_WsCreateXmlBuffer();
4656 test_WsSetOutput();
4657 test_WsSetOutputToBuffer();
4658 test_WsWriteStartElement();
4659 test_WsWriteStartAttribute();
4660 test_WsWriteType();
4661 test_basic_type();
4662 test_simple_struct_type();
4663 test_WsWriteElement();
4664 test_WsWriteValue();
4665 test_WsWriteAttribute();
4666 test_WsWriteStartCData();
4667 test_WsWriteXmlnsAttribute();
4668 test_WsGetPrefixFromNamespace();
4669 test_complex_struct_type();
4670 test_WsMoveWriter();
4671 test_WsGetWriterPosition();
4672 test_WsSetWriterPosition();
4673 test_WsWriteXmlBuffer();
4674 test_WsWriteNode();
4675 test_WsCopyNode();
4676 test_text_types();
4677 test_double();
4678 test_field_options();
4679 test_WsWriteText();
4680 test_WsWriteArray();
4681 test_escapes();
4682 test_write_option();
4683 test_datetime();
4684 test_repeating_element();
4685 test_WsWriteQualifiedName();
4686 test_WsWriteBytes();
4687 test_WsWriteChars();
4688 test_WsWriteCharsUtf8();
4689 test_binary_encoding();
4690 test_namespaces();
4691 test_dictionary();
4692 test_union_type();
4693 test_text_types_binary();
4694 test_repeating_element_choice();