webservices: Implement WsWriteCharsUtf8.
[wine.git] / dlls / webservices / tests / writer.c
blob1d1ed047069c56ecb3a6e7df93039e83683288b3
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 "webservices.h"
22 #include "wine/test.h"
24 #include <math.h>
25 #ifndef INFINITY
26 static inline float __port_infinity(void)
28 static const unsigned __inf_bytes = 0x7f800000;
29 return *(const float *)&__inf_bytes;
31 #define INFINITY __port_infinity()
32 #endif
34 #ifndef NAN
35 static inline float __port_nan(void)
37 static const unsigned __nan_bytes = 0x7fc00000;
38 return *(const float *)&__nan_bytes;
40 #define NAN __port_nan()
41 #endif
43 static HRESULT set_output( WS_XML_WRITER *writer )
45 WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
46 WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
47 return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
50 static void test_WsCreateWriter(void)
52 HRESULT hr;
53 WS_XML_WRITER *writer;
54 WS_XML_WRITER_PROPERTY prop;
55 ULONG size, max_depth, max_attrs, indent, trim_size, max_size, max_ns;
56 BOOL allow_fragment, write_decl, in_attr;
57 WS_CHARSET charset;
58 WS_BUFFERS buffers;
59 WS_BYTES bytes;
61 hr = WsCreateWriter( NULL, 0, NULL, NULL );
62 ok( hr == E_INVALIDARG, "got %08x\n", hr );
64 writer = NULL;
65 hr = WsCreateWriter( NULL, 0, &writer, NULL );
66 ok( hr == S_OK, "got %08x\n", hr );
67 ok( writer != NULL, "writer not set\n" );
69 /* can't retrieve properties before output is set */
70 max_depth = 0xdeadbeef;
71 size = sizeof(max_depth);
72 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
73 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
74 ok( max_depth == 0xdeadbeef, "max_depth set\n" );
76 hr = set_output( writer );
77 ok( hr == S_OK, "got %08x\n", hr );
79 /* check some defaults */
80 max_depth = 0xdeadbeef;
81 size = sizeof(max_depth);
82 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
83 ok( hr == S_OK, "got %08x\n", hr );
84 ok( max_depth == 32, "got %u\n", max_depth );
86 allow_fragment = TRUE;
87 size = sizeof(allow_fragment);
88 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT, &allow_fragment, size, NULL );
89 ok( hr == S_OK, "got %08x\n", hr );
90 ok( !allow_fragment, "got %d\n", allow_fragment );
92 max_attrs = 0xdeadbeef;
93 size = sizeof(max_attrs);
94 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, size, NULL );
95 ok( hr == S_OK, "got %08x\n", hr );
96 ok( max_attrs == 128, "got %u\n", max_attrs );
98 write_decl = TRUE;
99 size = sizeof(write_decl);
100 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_WRITE_DECLARATION, &write_decl, size, NULL );
101 ok( hr == S_OK, "got %08x\n", hr );
102 ok( !write_decl, "got %d\n", write_decl );
104 indent = 0xdeadbeef;
105 size = sizeof(indent);
106 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INDENT, &indent, size, NULL );
107 ok( hr == S_OK, "got %08x\n", hr );
108 ok( !indent, "got %u\n", indent );
110 trim_size = 0xdeadbeef;
111 size = sizeof(trim_size);
112 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, size, NULL );
113 ok( hr == S_OK, "got %08x\n", hr );
114 ok( trim_size == 4096, "got %u\n", trim_size );
116 charset = 0xdeadbeef;
117 size = sizeof(charset);
118 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_CHARSET, &charset, size, NULL );
119 ok( hr == S_OK, "got %08x\n", hr );
120 ok( charset == WS_CHARSET_UTF8, "got %u\n", charset );
122 buffers.bufferCount = 0xdeadbeef;
123 buffers.buffers = (WS_BYTES *)0xdeadbeef;
124 size = sizeof(buffers);
125 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFERS, &buffers, size, NULL );
126 ok( hr == S_OK, "got %08x\n", hr );
127 ok( !buffers.bufferCount, "got %u\n", buffers.bufferCount );
128 ok( !buffers.buffers, "got %p\n", buffers.buffers );
130 max_size = 0xdeadbeef;
131 size = sizeof(max_size);
132 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, size, NULL );
133 ok( hr == S_OK, "got %08x\n", hr );
134 ok( max_size == 65536, "got %u\n", max_size );
136 bytes.length = 0xdeadbeef;
137 bytes.bytes = (BYTE *)0xdeadbeef;
138 size = sizeof(buffers);
139 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
140 ok( hr == S_OK, "got %08x\n", hr );
141 ok( !bytes.length, "got %u\n", bytes.length );
142 ok( bytes.bytes != NULL, "got %p\n", bytes.bytes );
144 max_size = 0xdeadbeef;
145 size = sizeof(max_size);
146 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, size, NULL );
147 ok( hr == S_OK, "got %08x\n", hr );
148 ok( max_size == 65536, "got %u\n", max_size );
150 bytes.length = 0xdeadbeef;
151 bytes.bytes = (BYTE *)0xdeadbeef;
152 size = sizeof(bytes);
153 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INITIAL_BUFFER, &bytes, size, NULL );
154 ok( hr == S_OK, "got %08x\n", hr );
155 ok( !bytes.length, "got %u\n", bytes.length );
156 ok( !bytes.bytes, "got %p\n", bytes.bytes );
158 max_ns = 0xdeadbeef;
159 size = sizeof(max_ns);
160 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, size, NULL );
161 ok( hr == S_OK, "got %08x\n", hr );
162 ok( max_ns == 32, "got %u\n", max_ns );
163 WsFreeWriter( writer );
165 /* change a property */
166 max_depth = 16;
167 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
168 prop.value = &max_depth;
169 prop.valueSize = sizeof(max_depth);
170 hr = WsCreateWriter( &prop, 1, &writer, NULL );
171 ok( hr == S_OK, "got %08x\n", hr );
173 hr = set_output( writer );
174 ok( hr == S_OK, "got %08x\n", hr );
176 max_depth = 0xdeadbeef;
177 size = sizeof(max_depth);
178 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
179 ok( hr == S_OK, "got %08x\n", hr );
180 ok( max_depth == 16, "got %u\n", max_depth );
181 WsFreeWriter( writer );
183 /* show that some properties are read-only */
184 in_attr = TRUE;
185 prop.id = WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE;
186 prop.value = &in_attr;
187 prop.valueSize = sizeof(in_attr);
188 hr = WsCreateWriter( &prop, 1, &writer, NULL );
189 ok( hr == E_INVALIDARG, "got %08x\n", hr );
191 size = 1;
192 prop.id = WS_XML_WRITER_PROPERTY_BYTES_WRITTEN;
193 prop.value = &size;
194 prop.valueSize = sizeof(size);
195 hr = WsCreateWriter( &prop, 1, &writer, NULL );
196 ok( hr == E_INVALIDARG, "got %08x\n", hr );
198 size = 1;
199 prop.id = WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE;
200 prop.value = &size;
201 prop.valueSize = sizeof(size);
202 hr = WsCreateWriter( &prop, 1, &writer, NULL );
203 ok( hr == E_INVALIDARG, "got %08x\n", hr );
206 static void test_WsCreateXmlBuffer(void)
208 HRESULT hr;
209 WS_HEAP *heap;
210 WS_XML_WRITER *writer;
211 WS_XML_BUFFER *buffer;
212 WS_BYTES bytes;
213 ULONG size;
215 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
216 ok( hr == E_INVALIDARG, "got %08x\n", hr );
218 hr = WsCreateXmlBuffer( NULL, NULL, 0, &buffer, NULL );
219 ok( hr == E_INVALIDARG, "got %08x\n", hr );
221 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
222 ok( hr == S_OK, "got %08x\n", hr );
224 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
225 ok( hr == E_INVALIDARG, "got %08x\n", hr );
227 buffer = NULL;
228 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
229 ok( hr == S_OK, "got %08x\n", hr );
230 ok( buffer != NULL, "buffer not set\n" );
232 hr = WsCreateWriter( NULL, 0, &writer, NULL );
233 ok( hr == S_OK, "got %08x\n", hr );
235 size = sizeof(bytes);
236 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
237 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
239 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
240 ok( hr == S_OK, "got %08x\n", hr );
242 size = sizeof(bytes);
243 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
244 todo_wine ok( hr == E_INVALIDARG, "got %08x\n", hr );
246 WsFreeWriter( writer );
247 WsFreeHeap( heap );
250 static void test_WsSetOutput(void)
252 HRESULT hr;
253 WS_XML_WRITER *writer;
254 WS_XML_WRITER_PROPERTY prop;
255 WS_XML_WRITER_TEXT_ENCODING encoding;
256 WS_XML_WRITER_BUFFER_OUTPUT output;
257 ULONG size, max_depth;
259 hr = WsCreateWriter( NULL, 0, &writer, NULL );
260 ok( hr == S_OK, "got %08x\n", hr );
262 hr = WsSetOutput( NULL, NULL, NULL, NULL, 0, NULL );
263 ok( hr == E_INVALIDARG, "got %08x\n", hr );
265 encoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_TEXT;
266 encoding.charSet = WS_CHARSET_UTF8;
268 output.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
270 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
271 ok( hr == S_OK, "got %08x\n", hr );
273 /* multiple calls are allowed */
274 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
275 ok( hr == S_OK, "got %08x\n", hr );
277 /* writer properties can be set with WsSetOutput */
278 max_depth = 16;
279 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
280 prop.value = &max_depth;
281 prop.valueSize = sizeof(max_depth);
282 hr = WsSetOutput( writer, &encoding.encoding, &output.output, &prop, 1, NULL );
283 ok( hr == S_OK, "got %08x\n", hr );
285 max_depth = 0xdeadbeef;
286 size = sizeof(max_depth);
287 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
288 ok( hr == S_OK, "got %08x\n", hr );
289 ok( max_depth == 16, "got %u\n", max_depth );
290 WsFreeWriter( writer );
293 static void test_WsSetOutputToBuffer(void)
295 HRESULT hr;
296 WS_HEAP *heap;
297 WS_XML_BUFFER *buffer;
298 WS_XML_WRITER *writer;
299 WS_XML_WRITER_PROPERTY prop;
300 ULONG size, max_depth;
302 hr = WsSetOutputToBuffer( NULL, NULL, NULL, 0, NULL );
303 ok( hr == E_INVALIDARG, "got %08x\n", hr );
305 hr = WsCreateWriter( NULL, 0, &writer, NULL );
306 ok( hr == S_OK, "got %08x\n", hr );
308 hr = WsSetOutputToBuffer( writer, NULL, NULL, 0, NULL );
309 ok( hr == E_INVALIDARG, "got %08x\n", hr );
311 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
312 ok( hr == S_OK, "got %08x\n", hr );
314 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
315 ok( hr == S_OK, "got %08x\n", hr );
317 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
318 ok( hr == S_OK, "got %08x\n", hr );
320 /* multiple calls are allowed */
321 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
322 ok( hr == S_OK, "got %08x\n", hr );
324 /* writer properties can be set with WsSetOutputToBuffer */
325 max_depth = 16;
326 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
327 prop.value = &max_depth;
328 prop.valueSize = sizeof(max_depth);
329 hr = WsSetOutputToBuffer( writer, buffer, &prop, 1, NULL );
330 ok( hr == S_OK, "got %08x\n", hr );
332 max_depth = 0xdeadbeef;
333 size = sizeof(max_depth);
334 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
335 ok( hr == S_OK, "got %08x\n", hr );
336 ok( max_depth == 16, "got %u\n", max_depth );
338 WsFreeWriter( writer );
339 WsFreeHeap( heap );
342 static char strbuf[512];
343 static const char *debugstr_bytes( const BYTE *bytes, ULONG len )
345 const BYTE *src = bytes;
346 char *dst = strbuf;
348 while (len)
350 BYTE c = *src++;
351 if (dst - strbuf > sizeof(strbuf) - 7) break;
352 switch (c)
354 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
355 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
356 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
357 default:
358 if (c >= ' ' && c < 127) *dst++ = c;
359 else
361 sprintf( dst, "\\%02x", c );
362 dst += 3;
365 len--;
367 if (len)
369 *dst++ = '.';
370 *dst++ = '.';
371 *dst++ = '.';
373 *dst = 0;
374 return strbuf;
377 static void check_output( WS_XML_WRITER *writer, const char *expected, unsigned int line )
379 WS_BYTES bytes;
380 ULONG size = sizeof(bytes);
381 int len = strlen( expected );
382 HRESULT hr;
384 memset( &bytes, 0, sizeof(bytes) );
385 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
386 ok( hr == S_OK, "%u: got %08x\n", line, hr );
387 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
388 if (bytes.length != len) return;
389 ok( !memcmp( bytes.bytes, expected, len ),
390 "%u: got %s expected %s\n", line, debugstr_bytes(bytes.bytes, bytes.length), expected );
393 static void test_WsWriteStartElement(void)
395 HRESULT hr;
396 WS_XML_WRITER *writer;
397 WS_XML_STRING prefix = {1, (BYTE *)"p"}, ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
398 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"};
400 hr = WsCreateWriter( NULL, 0, &writer, NULL );
401 ok( hr == S_OK, "got %08x\n", hr );
403 hr = set_output( writer );
404 ok( hr == S_OK, "got %08x\n", hr );
406 hr = WsWriteStartElement( NULL, &prefix, &localname, &ns, NULL );
407 ok( hr == E_INVALIDARG, "got %08x\n", hr );
409 /* first call to WsWriteStartElement doesn't output anything */
410 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
411 ok( hr == S_OK, "got %08x\n", hr );
412 check_output( writer, "", __LINE__ );
414 /* two ways to close an element */
415 hr = WsWriteEndStartElement( writer, NULL );
416 ok( hr == S_OK, "got %08x\n", hr );
417 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
419 hr = WsWriteEndElement( writer, NULL );
420 ok( hr == S_OK, "got %08x\n", hr );
421 check_output( writer, "<p:a xmlns:p=\"ns\"></p:a>", __LINE__ );
423 hr = set_output( writer );
424 ok( hr == S_OK, "got %08x\n", hr );
426 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
427 ok( hr == S_OK, "got %08x\n", hr );
429 hr = WsWriteEndElement( writer, NULL );
430 ok( hr == S_OK, "got %08x\n", hr );
431 check_output( writer, "<p:a xmlns:p=\"ns\"/>", __LINE__ );
433 /* nested elements */
434 hr = set_output( writer );
435 ok( hr == S_OK, "got %08x\n", hr );
437 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
438 ok( hr == S_OK, "got %08x\n", hr );
439 check_output( writer, "", __LINE__ );
441 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
442 ok( hr == S_OK, "got %08x\n", hr );
443 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
445 hr = WsWriteEndElement( writer, NULL );
446 ok( hr == S_OK, "got %08x\n", hr );
447 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/>", __LINE__ );
449 hr = WsWriteEndElement( writer, NULL );
450 ok( hr == S_OK, "got %08x\n", hr );
451 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/></p:a>", __LINE__ );
453 hr = set_output( writer );
454 ok( hr == S_OK, "got %08x\n", hr );
456 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
457 ok( hr == S_OK, "got %08x\n", hr );
458 check_output( writer, "", __LINE__ );
460 hr = WsWriteStartElement( writer, NULL, &localname2, &ns2, NULL );
461 ok( hr == S_OK, "got %08x\n", hr );
462 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
464 hr = WsWriteEndElement( writer, NULL );
465 ok( hr == S_OK, "got %08x\n", hr );
466 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/>", __LINE__ );
468 hr = WsWriteEndElement( writer, NULL );
469 ok( hr == S_OK, "got %08x\n", hr );
470 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/></p:a>", __LINE__ );
472 WsFreeWriter( writer );
475 static void test_WsWriteStartAttribute(void)
477 HRESULT hr;
478 WS_XML_WRITER *writer;
479 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {3, (BYTE *)"str"}, ns = {2, (BYTE *)"ns"};
480 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
482 hr = WsCreateWriter( NULL, 0, &writer, NULL );
483 ok( hr == S_OK, "got %08x\n", hr );
485 hr = set_output( writer );
486 ok( hr == S_OK, "got %08x\n", hr );
488 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
489 ok( hr == S_OK, "got %08x\n", hr );
491 hr = WsWriteStartAttribute( NULL, &prefix, &localname, &ns, FALSE, NULL );
492 ok( hr == E_INVALIDARG, "got %08x\n", hr );
494 /* WsWriteStartAttribute doesn't output anything */
495 localname.length = 3;
496 localname.bytes = (BYTE *)"len";
497 hr = WsWriteStartAttribute( writer, &prefix, &localname, &ns, FALSE, NULL );
498 ok( hr == S_OK, "got %08x\n", hr );
499 check_output( writer, "", __LINE__ );
501 text.value.length = 1;
502 text.value.bytes = (BYTE *)"0";
503 hr = WsWriteText( writer, &text.text, NULL );
504 ok( hr == S_OK, "got %08x\n", hr );
505 check_output( writer, "", __LINE__ );
507 /* WsWriteEndAttribute doesn't output anything */
508 hr = WsWriteEndAttribute( writer, NULL );
509 ok( hr == S_OK, "got %08x\n", hr );
510 check_output( writer, "", __LINE__ );
512 hr = WsWriteEndElement( writer, NULL );
513 ok( hr == S_OK, "got %08x\n", hr );
514 check_output( writer, "<p:str p:len=\"0\" xmlns:p=\"ns\"/>", __LINE__ );
516 WsFreeWriter( writer );
519 static void test_WsWriteType(void)
521 static const WCHAR testW[] = {'t','e','s','t',0};
522 HRESULT hr;
523 WS_XML_WRITER *writer;
524 WS_XML_STRING prefix = {1, (BYTE*)"p"}, localname = {3, (BYTE *)"str"}, ns = {2, (BYTE *)"ns"};
525 const WCHAR *val_str;
527 hr = WsCreateWriter( NULL, 0, &writer, NULL );
528 ok( hr == S_OK, "got %08x\n", hr );
530 hr = set_output( writer );
531 ok( hr == S_OK, "got %08x\n", hr );
533 val_str = testW;
534 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
535 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
536 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
538 hr = set_output( writer );
539 ok( hr == S_OK, "got %08x\n", hr );
541 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
542 ok( hr == S_OK, "got %08x\n", hr );
544 /* required value */
545 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
546 WS_WRITE_REQUIRED_VALUE, NULL, sizeof(testW), NULL );
547 ok( hr == E_INVALIDARG, "got %08x\n", hr );
549 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
550 WS_WRITE_REQUIRED_VALUE, testW, sizeof(testW), NULL );
551 ok( hr == E_INVALIDARG, "got %08x\n", hr );
553 /* required pointer */
554 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
555 WS_WRITE_REQUIRED_POINTER, NULL, sizeof(val_str), NULL );
556 ok( hr == E_INVALIDARG, "got %08x\n", hr );
558 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
559 WS_WRITE_REQUIRED_VALUE, testW, sizeof(testW), NULL );
560 ok( hr == E_INVALIDARG, "got %08x\n", hr );
562 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
563 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(WCHAR **), NULL );
564 ok( hr == S_OK, "got %08x\n", hr );
565 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
567 hr = WsWriteEndElement( writer, NULL );
568 ok( hr == S_OK, "got %08x\n", hr );
569 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
571 hr = set_output( writer );
572 ok( hr == S_OK, "got %08x\n", hr );
574 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
575 ok( hr == S_OK, "got %08x\n", hr );
577 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
578 ok( hr == S_OK, "got %08x\n", hr );
580 val_str = testW;
581 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
582 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
583 ok( hr == S_OK, "got %08x\n", hr );
584 check_output( writer, "", __LINE__ );
586 hr = WsWriteEndAttribute( writer, NULL );
587 ok( hr == S_OK, "got %08x\n", hr );
588 check_output( writer, "", __LINE__ );
590 hr = WsWriteEndElement( writer, NULL );
591 ok( hr == S_OK, "got %08x\n", hr );
592 check_output( writer, "<p:str p:str=\"test\" xmlns:p=\"ns\"/>", __LINE__ );
594 hr = set_output( writer );
595 ok( hr == S_OK, "got %08x\n", hr );
597 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
598 ok( hr == S_OK, "got %08x\n", hr );
600 val_str = testW;
601 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
602 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
603 ok( hr == S_OK, "got %08x\n", hr );
604 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
606 hr = WsWriteEndElement( writer, NULL );
607 ok( hr == S_OK, "got %08x\n", hr );
608 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
610 WsFreeWriter( writer );
613 static void prepare_basic_type_test( WS_XML_WRITER *writer )
615 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
616 HRESULT hr;
618 hr = set_output( writer );
619 ok( hr == S_OK, "got %08x\n", hr );
620 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
621 ok( hr == S_OK, "got %08x\n", hr );
624 static void test_basic_type(void)
626 static WCHAR testW[] = {'t','e','s','t',0};
627 HRESULT hr;
628 WS_XML_WRITER *writer;
629 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, xmlstr;
630 GUID guid;
631 WCHAR *str;
632 WS_STRING string;
633 WS_BYTES bytes;
634 ULONG i;
635 static const struct
637 WS_TYPE type;
638 INT64 val;
639 ULONG size;
640 const char *result;
641 const char *result2;
643 tests[] =
645 { WS_BOOL_TYPE, TRUE, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
646 { WS_BOOL_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
647 { WS_INT8_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
648 { WS_INT16_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
649 { WS_INT32_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
650 "<t t=\"-2147483648\"/>" },
651 { WS_INT64_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
652 "<t t=\"-9223372036854775808\"/>" },
653 { WS_UINT8_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
654 { WS_UINT16_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
655 { WS_UINT32_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
656 { WS_UINT64_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
657 "<t t=\"18446744073709551615\"/>" },
660 hr = WsCreateWriter( NULL, 0, &writer, NULL );
661 ok( hr == S_OK, "got %08x\n", hr );
663 /* element content type mapping */
664 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
666 prepare_basic_type_test( writer );
667 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, tests[i].type, NULL,
668 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
669 ok( hr == S_OK, "%u: got %08x\n", i, hr );
671 hr = WsWriteEndElement( writer, NULL );
672 ok( hr == S_OK, "got %08x\n", hr );
673 check_output( writer, tests[i].result, __LINE__ );
676 /* element type mapping is the same as element content type mapping for basic types */
677 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
679 const INT64 *ptr = &tests[i].val;
681 prepare_basic_type_test( writer );
682 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL,
683 WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
684 ok( hr == S_OK, "%u: got %08x\n", i, hr );
686 hr = WsWriteEndElement( writer, NULL );
687 ok( hr == S_OK, "got %08x\n", hr );
688 check_output( writer, tests[i].result, __LINE__ );
691 /* attribute type mapping */
692 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
694 prepare_basic_type_test( writer );
695 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
696 ok( hr == S_OK, "got %08x\n", hr );
698 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, tests[i].type, NULL,
699 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
700 ok( hr == S_OK, "%u: got %08x\n", i, hr );
702 hr = WsWriteEndAttribute( writer, NULL );
703 ok( hr == S_OK, "got %08x\n", hr );
705 hr = WsWriteEndElement( writer, NULL );
706 ok( hr == S_OK, "got %08x\n", hr );
707 check_output( writer, tests[i].result2, __LINE__ );
710 prepare_basic_type_test( writer );
711 memset( &guid, 0, sizeof(guid) );
712 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_GUID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
713 &guid, sizeof(guid), NULL );
714 ok( hr == S_OK, "got %08x\n", hr );
715 hr = WsWriteEndElement( writer, NULL );
716 ok( hr == S_OK, "got %08x\n", hr );
717 check_output( writer, "<t>00000000-0000-0000-0000-000000000000</t>", __LINE__ );
719 prepare_basic_type_test( writer );
720 string.chars = testW;
721 string.length = 4;
722 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
723 &string, sizeof(string), NULL );
724 ok( hr == S_OK, "got %08x\n", hr );
725 hr = WsWriteEndElement( writer, NULL );
726 ok( hr == S_OK, "got %08x\n", hr );
727 check_output( writer, "<t>test</t>", __LINE__ );
729 prepare_basic_type_test( writer );
730 str = testW;
731 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL, WS_WRITE_REQUIRED_POINTER,
732 &str, sizeof(str), NULL );
733 ok( hr == S_OK, "got %08x\n", hr );
734 hr = WsWriteEndElement( writer, NULL );
735 ok( hr == S_OK, "got %08x\n", hr );
736 check_output( writer, "<t>test</t>", __LINE__ );
738 prepare_basic_type_test( writer );
739 xmlstr.bytes = (BYTE *)"test";
740 xmlstr.length = 4;
741 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
742 &xmlstr, sizeof(xmlstr), NULL );
743 ok( hr == S_OK, "got %08x\n", hr );
744 hr = WsWriteEndElement( writer, NULL );
745 ok( hr == S_OK, "got %08x\n", hr );
746 check_output( writer, "<t>test</t>", __LINE__ );
748 prepare_basic_type_test( writer );
749 bytes.bytes = (BYTE *)"test";
750 bytes.length = 4;
751 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
752 &bytes, sizeof(bytes), NULL );
753 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, "<t>dGVzdA==</t>", __LINE__ );
758 prepare_basic_type_test( writer );
759 bytes.length = 0;
760 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
761 &bytes, sizeof(bytes), NULL );
762 ok( hr == S_OK, "got %08x\n", hr );
763 hr = WsWriteEndElement( writer, NULL );
764 ok( hr == S_OK, "got %08x\n", hr );
765 check_output( writer, "<t/>", __LINE__ );
767 prepare_basic_type_test( writer );
768 bytes.bytes = NULL;
769 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
770 &bytes, sizeof(bytes), NULL );
771 ok( hr == S_OK, "got %08x\n", hr );
772 hr = WsWriteEndElement( writer, NULL );
773 ok( hr == S_OK, "got %08x\n", hr );
774 check_output( writer, "<t/>", __LINE__ );
776 prepare_basic_type_test( writer );
777 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_NILLABLE_VALUE,
778 &bytes, sizeof(bytes), NULL );
779 ok( hr == S_OK, "got %08x\n", hr );
780 hr = WsWriteEndElement( writer, NULL );
781 ok( hr == S_OK, "got %08x\n", hr );
782 check_output( writer, "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>",
783 __LINE__ );
785 WsFreeWriter( writer );
788 static void test_simple_struct_type(void)
790 static const WCHAR valueW[] = {'v','a','l','u','e',0};
791 HRESULT hr;
792 WS_XML_WRITER *writer;
793 WS_STRUCT_DESCRIPTION s;
794 WS_FIELD_DESCRIPTION f, *fields[1];
795 WS_XML_STRING localname = {6, (BYTE *)"struct"}, ns = {0, NULL};
796 struct test
798 const WCHAR *field;
799 } *test;
801 hr = WsCreateWriter( NULL, 0, &writer, NULL );
802 ok( hr == S_OK, "got %08x\n", hr );
804 hr = set_output( writer );
805 ok( hr == S_OK, "got %08x\n", hr );
807 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
808 ok( hr == S_OK, "got %08x\n", hr );
810 memset( &f, 0, sizeof(f) );
811 f.mapping = WS_TEXT_FIELD_MAPPING;
812 f.type = WS_WSZ_TYPE;
813 fields[0] = &f;
815 memset( &s, 0, sizeof(s) );
816 s.size = sizeof(struct test);
817 s.alignment = TYPE_ALIGNMENT(struct test);
818 s.fields = fields;
819 s.fieldCount = 1;
821 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
822 test->field = valueW;
823 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
824 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
825 ok( hr == E_INVALIDARG, "got %08x\n", hr );
827 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
828 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
829 ok( hr == E_INVALIDARG, "got %08x\n", hr );
831 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
832 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
833 ok( hr == S_OK, "got %08x\n", hr );
835 hr = WsWriteEndElement( writer, NULL );
836 ok( hr == S_OK, "got %08x\n", hr );
837 check_output( writer, "<struct>value</struct>", __LINE__ );
839 /* required value */
840 hr = set_output( writer );
841 ok( hr == S_OK, "got %08x\n", hr );
843 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
844 ok( hr == S_OK, "got %08x\n", hr );
846 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
847 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
848 ok( hr == S_OK, "got %08x\n", hr );
850 hr = WsWriteEndElement( writer, NULL );
851 ok( hr == S_OK, "got %08x\n", hr );
852 check_output( writer, "<struct>value</struct>", __LINE__ );
854 hr = set_output( writer );
855 ok( hr == S_OK, "got %08x\n", hr );
857 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
858 ok( hr == S_OK, "got %08x\n", hr );
860 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
861 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
862 ok( hr == S_OK, "got %08x\n", hr );
864 hr = WsWriteEndElement( writer, NULL );
865 ok( hr == S_OK, "got %08x\n", hr );
866 check_output( writer, "<struct>value</struct>", __LINE__ );
868 hr = set_output( writer );
869 ok( hr == S_OK, "got %08x\n", hr );
871 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
872 ok( hr == S_OK, "got %08x\n", hr );
874 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
875 ok( hr == S_OK, "got %08x\n", hr );
877 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
878 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
879 ok( hr == S_OK, "got %08x\n", hr );
881 hr = WsWriteEndAttribute( writer, NULL );
882 ok( hr == S_OK, "got %08x\n", hr );
884 hr = WsWriteEndElement( writer, NULL );
885 ok( hr == S_OK, "got %08x\n", hr );
886 check_output( writer, "<struct struct=\"value\"/>", __LINE__ );
888 HeapFree( GetProcessHeap(), 0, test );
889 WsFreeWriter( writer );
892 static void test_WsWriteElement(void)
894 static const WCHAR testW[] = {'t','e','s','t',0};
895 HRESULT hr;
896 WS_XML_WRITER *writer;
897 WS_STRUCT_DESCRIPTION s;
898 WS_FIELD_DESCRIPTION f, *fields[1];
899 WS_ELEMENT_DESCRIPTION desc;
900 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
901 struct test { const WCHAR *str; } *test;
903 hr = WsCreateWriter( NULL, 0, &writer, NULL );
904 ok( hr == S_OK, "got %08x\n", hr );
906 hr = set_output( writer );
907 ok( hr == S_OK, "got %08x\n", hr );
909 /* text field mapping */
910 memset( &f, 0, sizeof(f) );
911 f.mapping = WS_TEXT_FIELD_MAPPING;
912 f.type = WS_WSZ_TYPE;
913 fields[0] = &f;
915 memset( &s, 0, sizeof(s) );
916 s.size = sizeof(struct test);
917 s.alignment = TYPE_ALIGNMENT(struct test);
918 s.fields = fields;
919 s.fieldCount = 1;
921 desc.elementLocalName = &localname;
922 desc.elementNs = &ns;
923 desc.type = WS_STRUCT_TYPE;
924 desc.typeDescription = &s;
926 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
927 test->str = testW;
928 hr = WsWriteElement( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
929 ok( hr == E_INVALIDARG, "got %08x\n", hr );
931 hr = WsWriteElement( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
932 ok( hr == E_INVALIDARG, "got %08x\n", hr );
934 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
935 ok( hr == E_INVALIDARG, "got %08x\n", hr );
937 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
938 ok( hr == S_OK, "got %08x\n", hr );
939 check_output( writer, "<str>test</str>", __LINE__ );
941 hr = set_output( writer );
942 ok( hr == S_OK, "got %08x\n", hr );
944 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
945 ok( hr == S_OK, "got %08x\n", hr );
947 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
948 ok( hr == S_OK, "got %08x\n", hr );
949 check_output( writer, "<str><str>test</str>", __LINE__ );
951 hr = set_output( writer );
952 ok( hr == S_OK, "got %08x\n", hr );
954 /* attribute field mapping */
955 f.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
957 /* requires localName and ns to be set */
958 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
959 ok( hr == E_INVALIDARG, "got %08x\n", hr );
961 hr = set_output( writer );
962 ok( hr == S_OK, "got %08x\n", hr );
964 f.localName = &localname;
965 f.ns = &ns;
966 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
967 ok( hr == S_OK, "got %08x\n", hr );
968 check_output( writer, "<str str=\"test\"/>", __LINE__ );
970 HeapFree( GetProcessHeap(), 0, test );
971 WsFreeWriter( writer );
974 static void test_WsWriteValue(void)
976 HRESULT hr;
977 WS_XML_WRITER *writer;
978 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
979 ULONG i;
980 static const struct
982 WS_VALUE_TYPE type;
983 INT64 val;
984 ULONG size;
985 const char *result;
986 const char *result2;
988 tests[] =
990 { WS_BOOL_VALUE_TYPE, ~0, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
991 { WS_BOOL_VALUE_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
992 { WS_INT8_VALUE_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
993 { WS_INT16_VALUE_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
994 { WS_INT32_VALUE_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
995 "<t t=\"-2147483648\"/>" },
996 { WS_INT64_VALUE_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
997 "<t t=\"-9223372036854775808\"/>" },
998 { WS_UINT8_VALUE_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
999 { WS_UINT16_VALUE_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
1000 { WS_UINT32_VALUE_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
1001 { WS_UINT64_VALUE_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
1002 "<t t=\"18446744073709551615\"/>" },
1005 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1006 ok( hr == S_OK, "got %08x\n", hr );
1008 hr = set_output( writer );
1009 ok( hr == S_OK, "got %08x\n", hr );
1011 hr = WsWriteValue( NULL, tests[0].type, &tests[0].val, tests[0].size, NULL );
1012 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1014 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, tests[0].size, NULL );
1015 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1017 hr = set_output( writer );
1018 ok( hr == S_OK, "got %08x\n", hr );
1020 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1021 ok( hr == S_OK, "got %08x\n", hr );
1023 /* zero size */
1024 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, 0, NULL );
1025 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1027 hr = set_output( writer );
1028 ok( hr == S_OK, "got %08x\n", hr );
1030 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1031 ok( hr == S_OK, "got %08x\n", hr );
1033 /* NULL value */
1034 hr = WsWriteValue( writer, tests[0].type, NULL, 0, NULL );
1035 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1037 /* element type mapping */
1038 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
1040 hr = set_output( writer );
1041 ok( hr == S_OK, "got %08x\n", hr );
1043 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1044 ok( hr == S_OK, "got %08x\n", hr );
1046 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1047 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1049 hr = WsWriteEndElement( writer, NULL );
1050 ok( hr == S_OK, "got %08x\n", hr );
1051 check_output( writer, tests[i].result, __LINE__ );
1054 /* attribute type mapping */
1055 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
1057 hr = set_output( writer );
1058 ok( hr == S_OK, "got %08x\n", hr );
1060 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1061 ok( hr == S_OK, "got %08x\n", hr );
1063 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
1064 ok( hr == S_OK, "got %08x\n", hr );
1066 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1067 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1069 hr = WsWriteEndAttribute( writer, NULL );
1070 ok( hr == S_OK, "got %08x\n", hr );
1072 hr = WsWriteEndElement( writer, NULL );
1073 ok( hr == S_OK, "got %08x\n", hr );
1074 check_output( writer, tests[i].result2, __LINE__ );
1077 WsFreeWriter( writer );
1080 static void test_WsWriteAttribute(void)
1082 static const WCHAR testW[] = {'t','e','s','t',0};
1083 HRESULT hr;
1084 WS_XML_WRITER *writer;
1085 WS_STRUCT_DESCRIPTION s;
1086 WS_FIELD_DESCRIPTION f, *fields[1];
1087 WS_ATTRIBUTE_DESCRIPTION desc;
1088 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
1089 struct test { const WCHAR *str; } *test;
1091 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1092 ok( hr == S_OK, "got %08x\n", hr );
1094 hr = set_output( writer );
1095 ok( hr == S_OK, "got %08x\n", hr );
1097 /* text field mapping */
1098 memset( &f, 0, sizeof(f) );
1099 f.mapping = WS_TEXT_FIELD_MAPPING;
1100 f.type = WS_WSZ_TYPE;
1101 fields[0] = &f;
1103 memset( &s, 0, sizeof(s) );
1104 s.size = sizeof(struct test);
1105 s.alignment = TYPE_ALIGNMENT(struct test);
1106 s.fields = fields;
1107 s.fieldCount = 1;
1109 desc.attributeLocalName = &localname;
1110 desc.attributeNs = &ns;
1111 desc.type = WS_STRUCT_TYPE;
1112 desc.typeDescription = &s;
1114 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
1115 test->str = testW;
1116 hr = WsWriteAttribute( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1117 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1119 hr = WsWriteAttribute( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1120 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1122 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
1123 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1125 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1126 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1128 hr = set_output( writer );
1129 ok( hr == S_OK, "got %08x\n", hr );
1131 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1132 ok( hr == S_OK, "got %08x\n", hr );
1134 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1135 ok( hr == S_OK, "got %08x\n", hr );
1137 hr = WsWriteEndElement( writer, NULL );
1138 ok( hr == S_OK, "got %08x\n", hr );
1139 check_output( writer, "<str str=\"test\"/>", __LINE__ );
1141 HeapFree( GetProcessHeap(), 0, test );
1142 WsFreeWriter( writer );
1145 static void test_WsWriteStartCData(void)
1147 HRESULT hr;
1148 WS_XML_WRITER *writer;
1149 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1150 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
1152 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1153 ok( hr == S_OK, "got %08x\n", hr );
1155 hr = set_output( writer );
1156 ok( hr == S_OK, "got %08x\n", hr );
1158 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1159 ok( hr == S_OK, "got %08x\n", hr );
1161 hr = WsWriteEndCData( writer, NULL );
1162 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1164 hr = set_output( writer );
1165 ok( hr == S_OK, "got %08x\n", hr );
1167 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1168 ok( hr == S_OK, "got %08x\n", hr );
1169 check_output( writer, "", __LINE__ );
1171 hr = WsWriteStartCData( writer, NULL );
1172 ok( hr == S_OK, "got %08x\n", hr );
1173 check_output( writer, "<t><![CDATA[", __LINE__ );
1175 text.value.bytes = (BYTE *)"<data>";
1176 text.value.length = 6;
1177 hr = WsWriteText( writer, &text.text, NULL );
1178 ok( hr == S_OK, "got %08x\n", hr );
1179 check_output( writer, "<t><![CDATA[<data>", __LINE__ );
1181 hr = WsWriteEndCData( writer, NULL );
1182 ok( hr == S_OK, "got %08x\n", hr );
1183 check_output( writer, "<t><![CDATA[<data>]]>", __LINE__ );
1185 hr = WsWriteEndElement( writer, NULL );
1186 ok( hr == S_OK, "got %08x\n", hr );
1187 check_output( writer, "<t><![CDATA[<data>]]></t>", __LINE__ );
1189 WsFreeWriter( writer );
1192 static void check_output_buffer( WS_XML_BUFFER *buffer, const char *expected, unsigned int line )
1194 WS_XML_WRITER *writer;
1195 WS_BYTES bytes;
1196 ULONG size = sizeof(bytes);
1197 int len = strlen(expected);
1198 HRESULT hr;
1200 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1201 ok( hr == S_OK, "got %08x\n", hr );
1203 hr = set_output( writer );
1204 ok( hr == S_OK, "got %08x\n", hr );
1206 hr = WsWriteXmlBuffer( writer, buffer, NULL );
1207 ok( hr == S_OK, "got %08x\n", hr );
1209 memset( &bytes, 0, sizeof(bytes) );
1210 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
1211 ok( hr == S_OK, "%u: got %08x\n", line, hr );
1212 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
1213 if (bytes.length != len) return;
1214 ok( !memcmp( bytes.bytes, expected, len ), "%u: got %s expected %s\n", line, bytes.bytes, expected );
1216 WsFreeWriter( writer );
1219 static void prepare_xmlns_test( WS_XML_WRITER *writer, WS_HEAP **heap, WS_XML_BUFFER **buffer )
1221 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1222 HRESULT hr;
1224 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, heap, NULL );
1225 ok( hr == S_OK, "got %08x\n", hr );
1227 hr = WsCreateXmlBuffer( *heap, NULL, 0, buffer, NULL );
1228 ok( hr == S_OK, "got %08x\n", hr );
1230 hr = WsSetOutputToBuffer( writer, *buffer, NULL, 0, NULL );
1231 ok( hr == S_OK, "got %08x\n", hr );
1233 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
1234 ok( hr == S_OK, "got %08x\n", hr );
1237 static void test_WsWriteXmlnsAttribute(void)
1239 WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1240 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, prefix2 = {7, (BYTE *)"prefix2"};
1241 WS_XML_STRING xmlns = {6, (BYTE *)"xmlns"}, attr = {4, (BYTE *)"attr"};
1242 WS_XML_STRING localname = {1, (BYTE *)"u"};
1243 WS_HEAP *heap;
1244 WS_XML_BUFFER *buffer;
1245 WS_XML_WRITER *writer;
1246 HRESULT hr;
1248 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1249 ok( hr == S_OK, "got %08x\n", hr );
1251 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1252 ok( hr == S_OK, "got %08x\n", hr );
1254 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1255 ok( hr == S_OK, "got %08x\n", hr );
1257 hr = WsWriteXmlnsAttribute( NULL, NULL, NULL, FALSE, NULL );
1258 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1259 WsFreeHeap( heap );
1261 prepare_xmlns_test( writer, &heap, &buffer );
1262 hr = WsWriteXmlnsAttribute( writer, NULL, NULL, FALSE, NULL );
1263 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1264 WsFreeHeap( heap );
1266 prepare_xmlns_test( writer, &heap, &buffer );
1267 hr = WsWriteXmlnsAttribute( writer, &prefix2, NULL, FALSE, NULL );
1268 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1270 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1271 ok( hr == S_OK, "got %08x\n", hr );
1272 hr = WsWriteXmlnsAttribute( writer, NULL, &ns, FALSE, NULL );
1273 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1274 WsFreeHeap( heap );
1276 /* no prefix */
1277 prepare_xmlns_test( writer, &heap, &buffer );
1278 hr = WsWriteXmlnsAttribute( writer, NULL, &ns2, FALSE, NULL );
1279 ok( hr == S_OK, "got %08x\n", hr );
1280 hr = WsWriteEndElement( writer, NULL );
1281 ok( hr == S_OK, "got %08x\n", hr );
1282 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\" xmlns=\"ns2\"/>", __LINE__ );
1283 WsFreeHeap( heap );
1285 /* prefix */
1286 prepare_xmlns_test( writer, &heap, &buffer );
1287 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1288 ok( hr == S_OK, "got %08x\n", hr );
1289 hr = WsWriteEndElement( writer, NULL );
1290 ok( hr == S_OK, "got %08x\n", hr );
1291 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns2\" xmlns:prefix=\"ns\"/>", __LINE__ );
1292 WsFreeHeap( heap );
1294 /* implicitly set element prefix namespace */
1295 prepare_xmlns_test( writer, &heap, &buffer );
1296 hr = WsWriteEndElement( writer, NULL );
1297 ok( hr == S_OK, "got %08x\n", hr );
1298 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\"/>", __LINE__ );
1299 WsFreeHeap( heap );
1301 /* explicitly set element prefix namespace */
1302 prepare_xmlns_test( writer, &heap, &buffer );
1303 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1304 ok( hr == S_OK, "got %08x\n", hr );
1305 hr = WsWriteEndElement( writer, NULL );
1306 ok( hr == S_OK, "got %08x\n", hr );
1307 check_output_buffer( buffer, "<prefix:t xmlns:prefix='ns'/>", __LINE__ );
1308 WsFreeHeap( heap );
1310 /* repeated calls, same namespace */
1311 prepare_xmlns_test( writer, &heap, &buffer );
1312 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1313 ok( hr == S_OK, "got %08x\n", hr );
1314 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1315 ok( hr == S_OK, "got %08x\n", hr );
1316 hr = WsWriteEndElement( writer, NULL );
1317 ok( hr == S_OK, "got %08x\n", hr );
1318 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns\" xmlns:prefix=\"ns\"/>", __LINE__ );
1319 WsFreeHeap( heap );
1321 /* repeated calls, different namespace */
1322 prepare_xmlns_test( writer, &heap, &buffer );
1323 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1324 ok( hr == S_OK, "got %08x\n", hr );
1325 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1326 ok( hr == S_OK, "got %08x\n", hr );
1327 hr = WsWriteEndElement( writer, NULL );
1328 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1329 WsFreeHeap( heap );
1331 /* single quotes */
1332 prepare_xmlns_test( writer, &heap, &buffer );
1333 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, TRUE, NULL );
1334 ok( hr == S_OK, "got %08x\n", hr );
1335 hr = WsWriteEndElement( writer, NULL );
1336 ok( hr == S_OK, "got %08x\n", hr );
1337 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns' xmlns:prefix=\"ns\"/>", __LINE__ );
1338 WsFreeHeap( heap );
1340 /* different namespace, different prefix */
1341 prepare_xmlns_test( writer, &heap, &buffer );
1342 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1343 ok( hr == S_OK, "got %08x\n", hr );
1344 hr = WsWriteEndElement( writer, NULL );
1345 ok( hr == S_OK, "got %08x\n", hr );
1346 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"/>", __LINE__ );
1347 WsFreeHeap( heap );
1349 /* different namespace, same prefix */
1350 prepare_xmlns_test( writer, &heap, &buffer );
1351 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns2, TRUE, NULL );
1352 ok( hr == S_OK, "got %08x\n", hr );
1353 hr = WsWriteEndElement( writer, NULL );
1354 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1355 WsFreeHeap( heap );
1357 /* regular attribute */
1358 prepare_xmlns_test( writer, &heap, &buffer );
1359 hr = WsWriteStartAttribute( writer, &xmlns, &prefix2, &ns2, TRUE, NULL );
1360 ok( hr == S_OK, "got %08x\n", hr );
1361 hr = WsWriteEndAttribute( writer, NULL );
1362 ok( hr == S_OK, "got %08x\n", hr );
1363 hr = WsWriteEndElement( writer, NULL );
1364 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1365 WsFreeHeap( heap );
1367 /* attribute order */
1368 prepare_xmlns_test( writer, &heap, &buffer );
1369 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1370 ok( hr == S_OK, "got %08x\n", hr );
1371 hr = WsWriteStartAttribute( writer, &prefix, &attr, &ns, TRUE, NULL );
1372 ok( hr == S_OK, "got %08x\n", hr );
1373 hr = WsWriteEndAttribute( writer, NULL );
1374 ok( hr == S_OK, "got %08x\n", hr );
1375 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1376 ok( hr == S_OK, "got %08x\n", hr );
1377 hr = WsWriteEndElement( writer, NULL );
1378 ok( hr == S_OK, "got %08x\n", hr );
1379 check_output_buffer( buffer, "<prefix:t prefix:attr='' xmlns:prefix='ns' xmlns:prefix2='ns2'/>", __LINE__ );
1380 WsFreeHeap( heap );
1382 /* scope */
1383 prepare_xmlns_test( writer, &heap, &buffer );
1384 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1385 ok( hr == S_OK, "got %08x\n", hr );
1386 hr = WsWriteStartElement( writer, &prefix2, &localname, &ns2, NULL );
1387 ok( hr == S_OK, "got %08x\n", hr );
1388 hr = WsWriteEndElement( writer, NULL );
1389 ok( hr == S_OK, "got %08x\n", hr );
1390 hr = WsWriteEndElement( writer, NULL );
1391 ok( hr == S_OK, "got %08x\n", hr );
1392 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"><prefix2:u/></prefix:t>",
1393 __LINE__ );
1394 WsFreeHeap( heap );
1396 WsFreeWriter( writer );
1399 static void prepare_prefix_test( WS_XML_WRITER *writer )
1401 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1402 HRESULT hr;
1404 hr = set_output( writer );
1405 ok( hr == S_OK, "got %08x\n", hr );
1406 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1407 ok( hr == S_OK, "got %08x\n", hr );
1408 hr = WsWriteEndStartElement( writer, NULL );
1409 ok( hr == S_OK, "got %08x\n", hr );
1412 static void test_WsGetPrefixFromNamespace(void)
1414 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, *prefix;
1415 const WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1416 WS_XML_WRITER *writer;
1417 HRESULT hr;
1419 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1420 ok( hr == S_OK, "got %08x\n", hr );
1422 hr = set_output( writer );
1423 ok( hr == S_OK, "got %08x\n", hr );
1424 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1425 ok( hr == S_OK, "got %08x\n", hr );
1427 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, NULL, NULL );
1428 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1430 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, &prefix, NULL );
1431 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1433 hr = WsGetPrefixFromNamespace( writer, NULL, FALSE, &prefix, NULL );
1434 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1436 /* element must be committed */
1437 hr = set_output( writer );
1438 ok( hr == S_OK, "got %08x\n", hr );
1439 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1440 ok( hr == S_OK, "got %08x\n", hr );
1441 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1442 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1444 /* but writer can't be positioned on end element node */
1445 hr = set_output( writer );
1446 ok( hr == S_OK, "got %08x\n", hr );
1447 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1448 ok( hr == S_OK, "got %08x\n", hr );
1449 hr = WsWriteEndElement( writer, NULL );
1450 ok( hr == S_OK, "got %08x\n", hr );
1451 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1452 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1454 /* required = TRUE */
1455 prefix = NULL;
1456 prepare_prefix_test( writer );
1457 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1458 ok( hr == S_OK, "got %08x\n", hr );
1459 ok( prefix != NULL, "prefix not set\n" );
1460 if (prefix)
1462 ok( prefix->length == 1, "got %u\n", prefix->length );
1463 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1466 prefix = (const WS_XML_STRING *)0xdeadbeef;
1467 hr = WsGetPrefixFromNamespace( writer, &ns2, TRUE, &prefix, NULL );
1468 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1469 ok( prefix == (const WS_XML_STRING *)0xdeadbeef, "prefix set\n" );
1471 /* required = FALSE */
1472 prefix = NULL;
1473 prepare_prefix_test( writer );
1474 hr = WsGetPrefixFromNamespace( writer, &ns, FALSE, &prefix, NULL );
1475 ok( hr == S_OK, "got %08x\n", hr );
1476 ok( prefix != NULL, "prefix not set\n" );
1477 if (prefix)
1479 ok( prefix->length == 1, "got %u\n", prefix->length );
1480 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1483 prefix = (const WS_XML_STRING *)0xdeadbeef;
1484 hr = WsGetPrefixFromNamespace( writer, &ns2, FALSE, &prefix, NULL );
1485 ok( hr == S_FALSE, "got %08x\n", hr );
1486 ok( prefix == NULL, "prefix not set\n" );
1488 WsFreeWriter( writer );
1491 static void test_complex_struct_type(void)
1493 static const char expected[] =
1494 "<o:OfficeConfig xmlns:o=\"urn:schemas-microsoft-com:office:office\">"
1495 "<o:services o:GenerationTime=\"2015-09-03T18:47:54\"/>"
1496 "</o:OfficeConfig>";
1497 static const WCHAR timestampW[] =
1498 {'2','0','1','5','-','0','9','-','0','3','T','1','8',':','4','7',':','5','4',0};
1499 WS_XML_STRING str_officeconfig = {12, (BYTE *)"OfficeConfig"};
1500 WS_XML_STRING str_services = {8, (BYTE *)"services"};
1501 WS_XML_STRING str_generationtime = {14, (BYTE *)"GenerationTime"};
1502 WS_XML_STRING ns = {39, (BYTE *)"urn:schemas-microsoft-com:office:office"};
1503 WS_XML_STRING prefix = {1, (BYTE *)"o"};
1504 DWORD size;
1505 HRESULT hr;
1506 WS_HEAP *heap;
1507 WS_XML_BUFFER *buffer;
1508 WS_XML_WRITER *writer;
1509 WS_STRUCT_DESCRIPTION s, s2;
1510 WS_FIELD_DESCRIPTION f, f2, *fields[1], *fields2[1];
1511 struct services
1513 const WCHAR *generationtime;
1515 struct officeconfig
1517 struct services *services;
1518 } *test;
1520 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1521 ok( hr == S_OK, "got %08x\n", hr );
1523 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1524 ok( hr == S_OK, "got %08x\n", hr );
1526 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1527 ok( hr == S_OK, "got %08x\n", hr );
1529 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1530 ok( hr == S_OK, "got %08x\n", hr );
1532 hr = WsWriteStartElement( writer, &prefix, &str_officeconfig, &ns, NULL );
1533 ok( hr == S_OK, "got %08x\n", hr );
1535 memset( &f2, 0, sizeof(f2) );
1536 f2.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
1537 f2.localName = &str_generationtime;
1538 f2.ns = &ns;
1539 f2.type = WS_WSZ_TYPE;
1540 f2.options = WS_FIELD_OPTIONAL;
1541 fields2[0] = &f2;
1543 memset( &s2, 0, sizeof(s2) );
1544 s2.size = sizeof(*test->services);
1545 s2.alignment = 4;
1546 s2.fields = fields2;
1547 s2.fieldCount = 1;
1548 s2.typeLocalName = &str_services;
1549 s2.typeNs = &ns;
1551 memset( &f, 0, sizeof(f) );
1552 f.mapping = WS_ELEMENT_FIELD_MAPPING;
1553 f.localName = &str_services;
1554 f.ns = &ns;
1555 f.type = WS_STRUCT_TYPE;
1556 f.typeDescription = &s2;
1557 f.options = WS_FIELD_POINTER;
1558 fields[0] = &f;
1560 memset( &s, 0, sizeof(s) );
1561 s.size = sizeof(*test);
1562 s.alignment = 4;
1563 s.fields = fields;
1564 s.fieldCount = 1;
1565 s.typeLocalName = &str_officeconfig;
1566 s.typeNs = &ns;
1568 size = sizeof(struct officeconfig) + sizeof(struct services);
1569 test = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
1570 test->services = (struct services *)(test + 1);
1571 test->services->generationtime = timestampW;
1572 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
1573 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1574 ok( hr == S_OK, "got %08x\n", hr );
1576 hr = WsWriteEndElement( writer, NULL );
1577 ok( hr == S_OK, "got %08x\n", hr );
1578 check_output_buffer( buffer, expected, __LINE__ );
1580 HeapFree( GetProcessHeap(), 0, test );
1581 WsFreeWriter( writer );
1582 WsFreeHeap( heap );
1585 static void test_WsMoveWriter(void)
1587 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"}, ns = {0, NULL};
1588 WS_HEAP *heap;
1589 WS_XML_WRITER *writer;
1590 WS_XML_BUFFER *buffer;
1591 HRESULT hr;
1593 hr = WsMoveWriter( NULL, WS_MOVE_TO_EOF, NULL, NULL );
1594 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1596 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1597 ok( hr == S_OK, "got %08x\n", hr );
1599 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1600 ok( hr == S_OK, "got %08x\n", hr );
1602 hr = set_output( writer );
1603 ok( hr == S_OK, "got %08x\n", hr );
1605 /* writer must be set to an XML buffer */
1606 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1607 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1609 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1610 ok( hr == S_OK, "got %08x\n", hr );
1612 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1613 ok( hr == S_OK, "got %08x\n", hr );
1615 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1616 ok( hr == S_OK, "got %08x\n", hr );
1618 /* <a><b/></a> */
1619 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1620 ok( hr == S_OK, "got %08x\n", hr );
1622 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
1623 ok( hr == S_OK, "got %08x\n", hr );
1625 hr = WsWriteEndElement( writer, NULL );
1626 ok( hr == S_OK, "got %08x\n", hr );
1628 hr = WsWriteEndElement( writer, NULL );
1629 ok( hr == S_OK, "got %08x\n", hr );
1631 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1632 ok( hr == S_OK, "got %08x\n", hr );
1634 hr = WsMoveWriter( writer, WS_MOVE_TO_ROOT_ELEMENT, NULL, NULL );
1635 ok( hr == S_OK, "got %08x\n", hr );
1637 hr = WsMoveWriter( writer, WS_MOVE_TO_CHILD_ELEMENT, NULL, NULL );
1638 ok( hr == S_OK, "got %08x\n", hr );
1640 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1641 ok( hr == S_OK, "got %08x\n", hr );
1643 hr = WsMoveWriter( writer, WS_MOVE_TO_PARENT_ELEMENT, NULL, NULL );
1644 ok( hr == S_OK, "got %08x\n", hr );
1646 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1647 ok( hr == S_OK, "got %08x\n", hr );
1649 hr = WsMoveWriter( writer, WS_MOVE_TO_BOF, NULL, NULL );
1650 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1652 WsFreeWriter( writer );
1653 WsFreeHeap( heap );
1656 static void test_WsGetWriterPosition(void)
1658 WS_HEAP *heap;
1659 WS_XML_WRITER *writer;
1660 WS_XML_BUFFER *buffer;
1661 WS_XML_NODE_POSITION pos;
1662 HRESULT hr;
1664 hr = WsGetWriterPosition( NULL, NULL, NULL );
1665 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1667 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1668 ok( hr == S_OK, "got %08x\n", hr );
1670 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1671 ok( hr == S_OK, "got %08x\n", hr );
1673 hr = WsGetWriterPosition( writer, &pos, NULL );
1674 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1676 hr = set_output( writer );
1677 ok( hr == S_OK, "got %08x\n", hr );
1679 /* writer must be set to an XML buffer */
1680 hr = WsGetWriterPosition( writer, &pos, NULL );
1681 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1683 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1684 ok( hr == S_OK, "got %08x\n", hr );
1686 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1687 ok( hr == S_OK, "got %08x\n", hr );
1689 hr = WsGetWriterPosition( writer, NULL, NULL );
1690 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1692 pos.buffer = pos.node = NULL;
1693 hr = WsGetWriterPosition( writer, &pos, NULL );
1694 ok( hr == S_OK, "got %08x\n", hr );
1695 ok( pos.buffer != NULL, "buffer not set\n" );
1696 ok( pos.node != NULL, "node not set\n" );
1698 WsFreeWriter( writer );
1699 WsFreeHeap( heap );
1702 static void test_WsSetWriterPosition(void)
1704 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1705 WS_HEAP *heap;
1706 WS_XML_WRITER *writer;
1707 WS_XML_BUFFER *buf1, *buf2;
1708 WS_XML_NODE_POSITION pos;
1709 HRESULT hr;
1711 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1712 ok( hr == S_OK, "got %08x\n", hr );
1714 hr = WsSetWriterPosition( NULL, NULL, NULL );
1715 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1717 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1718 ok( hr == S_OK, "got %08x\n", hr );
1720 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf1, NULL );
1721 ok( hr == S_OK, "got %08x\n", hr );
1723 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1724 ok( hr == S_OK, "got %08x\n", hr );
1726 hr = WsSetWriterPosition( writer, NULL, NULL );
1727 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1729 pos.buffer = pos.node = NULL;
1730 hr = WsGetWriterPosition( writer, &pos, NULL );
1731 ok( hr == S_OK, "got %08x\n", hr );
1732 ok( pos.buffer == buf1, "wrong buffer\n" );
1733 ok( pos.node != NULL, "node not set\n" );
1735 hr = WsSetWriterPosition( writer, &pos, NULL );
1736 ok( hr == S_OK, "got %08x\n", hr );
1738 /* different buffer */
1739 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf2, NULL );
1740 ok( hr == S_OK, "got %08x\n", hr );
1742 pos.buffer = buf2;
1743 hr = WsSetWriterPosition( writer, &pos, NULL );
1744 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1746 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1747 ok( hr == S_OK, "got %08x\n", hr );
1749 /* try to write at non-final position */
1750 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1751 ok( hr == S_OK, "got %08x\n", hr );
1753 pos.buffer = pos.node = NULL;
1754 hr = WsGetWriterPosition( writer, &pos, NULL );
1755 ok( hr == S_OK, "got %08x\n", hr );
1756 ok( pos.buffer == buf1, "wrong buffer\n" );
1757 ok( pos.node != NULL, "node not set\n" );
1759 hr = WsWriteEndElement( writer, NULL );
1760 ok( hr == S_OK, "got %08x\n", hr );
1761 check_output_buffer( buf1, "<t/>", __LINE__ );
1763 hr = WsSetWriterPosition( writer, &pos, NULL );
1764 ok( hr == S_OK, "got %08x\n", hr );
1766 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1767 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1769 WsFreeWriter( writer );
1770 WsFreeHeap( heap );
1773 static void test_WsWriteXmlBuffer(void)
1775 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1776 WS_XML_WRITER *writer1, *writer2;
1777 WS_XML_BUFFER *buffer1, *buffer2;
1778 WS_HEAP *heap;
1779 HRESULT hr;
1781 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1782 ok( hr == S_OK, "got %08x\n", hr );
1784 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
1785 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1787 hr = WsCreateWriter( NULL, 0, &writer1, NULL );
1788 ok( hr == S_OK, "got %08x\n", hr );
1790 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
1791 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1793 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer1, NULL );
1794 ok( hr == S_OK, "got %08x\n", hr );
1796 hr = WsSetOutputToBuffer( writer1, buffer1, NULL, 0, NULL );
1797 ok( hr == S_OK, "got %08x\n", hr );
1799 hr = WsWriteStartElement( writer1, NULL, &localname, &ns, NULL );
1800 ok( hr == S_OK, "got %08x\n", hr );
1802 hr = WsWriteEndElement( writer1, NULL );
1803 ok( hr == S_OK, "got %08x\n", hr );
1804 check_output_buffer( buffer1, "<t/>", __LINE__ );
1806 hr = WsCreateWriter( NULL, 0, &writer2, NULL );
1807 ok( hr == S_OK, "got %08x\n", hr );
1809 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer2, NULL );
1810 ok( hr == S_OK, "got %08x\n", hr );
1812 hr = WsSetOutputToBuffer( writer2, buffer2, NULL, 0, NULL );
1813 ok( hr == S_OK, "got %08x\n", hr );
1815 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1816 ok( hr == S_OK, "got %08x\n", hr );
1817 check_output_buffer( buffer2, "<t/>", __LINE__ );
1819 hr = WsMoveWriter( writer2, WS_MOVE_TO_PREVIOUS_ELEMENT, NULL, NULL );
1820 todo_wine ok( hr == S_OK, "got %08x\n", hr );
1822 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1823 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1825 WsFreeWriter( writer1 );
1826 WsFreeWriter( writer2 );
1827 WsFreeHeap( heap );
1830 static void test_WsWriteNode(void)
1832 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {4, (BYTE *)"attr"}, ns = {0, NULL};
1833 WS_XML_WRITER *writer;
1834 WS_XML_BUFFER *buffer;
1835 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
1836 WS_XML_ATTRIBUTE attr, *attrs[1];
1837 WS_XML_ELEMENT_NODE elem;
1838 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
1839 WS_XML_NODE node;
1840 WS_XML_TEXT_NODE text = {{WS_XML_NODE_TYPE_TEXT}};
1841 WS_HEAP *heap;
1842 HRESULT hr;
1844 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1845 ok( hr == S_OK, "got %08x\n", hr );
1847 hr = WsWriteNode( NULL, NULL, NULL );
1848 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1850 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1851 ok( hr == S_OK, "got %08x\n", hr );
1853 hr = WsWriteNode( writer, NULL, NULL );
1854 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1856 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1857 ok( hr == S_OK, "got %08x\n", hr );
1859 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1860 ok( hr == S_OK, "got %08x\n", hr );
1862 utf8.value.bytes = (BYTE *)"value";
1863 utf8.value.length = sizeof("value") - 1;
1865 attr.singleQuote = TRUE;
1866 attr.isXmlNs = FALSE;
1867 attr.prefix = NULL;
1868 attr.localName = &localname2;
1869 attr.ns = &ns;
1870 attr.value = &utf8.text;
1871 attrs[0] = &attr;
1873 elem.node.nodeType = WS_XML_NODE_TYPE_ELEMENT;
1874 elem.prefix = NULL;
1875 elem.localName = &localname;
1876 elem.ns = &ns;
1877 elem.attributeCount = 1;
1878 elem.attributes = attrs;
1879 elem.isEmpty = FALSE;
1880 hr = WsWriteNode( writer, &elem.node, NULL );
1881 ok( hr == S_OK, "got %08x\n", hr );
1883 comment.value.bytes = (BYTE *)"comment";
1884 comment.value.length = sizeof("comment") - 1;
1885 hr = WsWriteNode( writer, &comment.node, NULL );
1886 ok( hr == S_OK, "got %08x\n", hr );
1888 node.nodeType = WS_XML_NODE_TYPE_EOF;
1889 hr = WsWriteNode( writer, &node, NULL );
1890 ok( hr == S_OK, "got %08x\n", hr );
1892 node.nodeType = WS_XML_NODE_TYPE_BOF;
1893 hr = WsWriteNode( writer, &node, NULL );
1894 ok( hr == S_OK, "got %08x\n", hr );
1896 node.nodeType = WS_XML_NODE_TYPE_CDATA;
1897 hr = WsWriteNode( writer, &node, NULL );
1898 ok( hr == S_OK, "got %08x\n", hr );
1900 utf8.value.bytes = (BYTE *)"cdata";
1901 utf8.value.length = sizeof("cdata") - 1;
1902 text.text = &utf8.text;
1903 hr = WsWriteNode( writer, &text.node, NULL );
1904 ok( hr == S_OK, "got %08x\n", hr );
1906 node.nodeType = WS_XML_NODE_TYPE_END_CDATA;
1907 hr = WsWriteNode( writer, &node, NULL );
1908 ok( hr == S_OK, "got %08x\n", hr );
1910 utf8.value.bytes = (BYTE *)"text";
1911 utf8.value.length = sizeof("text") - 1;
1912 hr = WsWriteNode( writer, &text.node, NULL );
1913 ok( hr == S_OK, "got %08x\n", hr );
1915 node.nodeType = WS_XML_NODE_TYPE_END_ELEMENT;
1916 hr = WsWriteNode( writer, &node, NULL );
1917 ok( hr == S_OK, "got %08x\n", hr );
1918 check_output_buffer( buffer, "<t attr='value'><!--comment--><![CDATA[cdata]]>text</t>", __LINE__ );
1920 WsFreeWriter( writer );
1921 WsFreeHeap( heap );
1924 static HRESULT set_input( WS_XML_READER *reader, const char *data, ULONG size )
1926 WS_XML_READER_TEXT_ENCODING enc;
1927 WS_XML_READER_BUFFER_INPUT input;
1929 enc.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT;
1930 enc.charSet = WS_CHARSET_AUTO;
1932 input.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
1933 input.encodedData = (void *)data;
1934 input.encodedDataSize = size;
1936 return WsSetInput( reader, &enc.encoding, &input.input, NULL, 0, NULL );
1939 static void test_WsCopyNode(void)
1941 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"}, ns = {0, NULL};
1942 WS_XML_NODE_POSITION pos, pos2;
1943 WS_XML_WRITER *writer;
1944 WS_XML_READER *reader;
1945 WS_XML_BUFFER *buffer;
1946 WS_HEAP *heap;
1947 HRESULT hr;
1949 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1950 ok( hr == S_OK, "got %08x\n", hr );
1952 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1953 ok( hr == S_OK, "got %08x\n", hr );
1955 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1956 ok( hr == S_OK, "got %08x\n", hr );
1958 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1959 ok( hr == S_OK, "got %08x\n", hr );
1961 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1962 ok( hr == S_OK, "got %08x\n", hr );
1964 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
1965 ok( hr == S_OK, "got %08x\n", hr );
1967 hr = WsWriteEndElement( writer, NULL );
1968 ok( hr == S_OK, "got %08x\n", hr );
1970 hr = WsGetWriterPosition( writer, &pos, NULL );
1971 ok( hr == S_OK, "got %08x\n", hr );
1973 hr = WsWriteEndElement( writer, NULL );
1974 ok( hr == S_OK, "got %08x\n", hr );
1975 check_output_buffer( buffer, "<t><u/></t>", __LINE__ );
1977 hr = WsCreateReader( NULL, 0, &reader, NULL );
1978 ok( hr == S_OK, "got %08x\n", hr );
1980 hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
1981 ok( hr == S_OK, "got %08x\n", hr );
1983 hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
1984 ok( hr == S_OK, "got %08x\n", hr );
1986 hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
1987 ok( hr == S_OK, "got %08x\n", hr );
1989 hr = WsSetWriterPosition( writer, &pos, NULL );
1990 ok( hr == S_OK, "got %08x\n", hr );
1992 hr = WsCopyNode( writer, reader, NULL );
1993 ok( hr == S_OK, "got %08x\n", hr );
1994 check_output_buffer( buffer, "<t><u/><v/></t>", __LINE__ );
1996 hr = WsGetWriterPosition( writer, &pos2, NULL );
1997 ok( hr == S_OK, "got %08x\n", hr );
1998 ok( pos2.buffer == pos.buffer, "wrong buffer\n" );
1999 ok( pos2.node == pos.node, "wrong node\n" );
2001 WsFreeReader( reader );
2002 WsFreeWriter( writer );
2003 WsFreeHeap( heap );
2006 static void test_text_types(void)
2008 static const WCHAR utf16W[] = {'u','t','f','1','6'};
2009 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2010 WS_XML_WRITER *writer;
2011 static const WS_XML_UTF8_TEXT val_utf8 = { {WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"utf8"} };
2012 static WS_XML_UTF16_TEXT val_utf16 = { {WS_XML_TEXT_TYPE_UTF16} };
2013 static const WS_XML_GUID_TEXT val_guid = { {WS_XML_TEXT_TYPE_GUID} };
2014 static const WS_XML_UNIQUE_ID_TEXT val_urn = { {WS_XML_TEXT_TYPE_UNIQUE_ID} };
2015 static const WS_XML_BOOL_TEXT val_bool = { {WS_XML_TEXT_TYPE_BOOL}, TRUE };
2016 static const WS_XML_INT32_TEXT val_int32 = { {WS_XML_TEXT_TYPE_INT32}, -2147483647 - 1 };
2017 static const WS_XML_INT64_TEXT val_int64 = { {WS_XML_TEXT_TYPE_INT64}, -9223372036854775807 - 1 };
2018 static const WS_XML_UINT64_TEXT val_uint64 = { {WS_XML_TEXT_TYPE_UINT64}, ~0 };
2019 static const WS_XML_DATETIME_TEXT val_datetime = { {WS_XML_TEXT_TYPE_DATETIME}, {0, WS_DATETIME_FORMAT_UTC} };
2020 static const WS_XML_DOUBLE_TEXT val_double = { {WS_XML_TEXT_TYPE_DOUBLE}, 1.1 };
2021 static const WS_XML_BASE64_TEXT val_base64 = { {WS_XML_TEXT_TYPE_BASE64}, (BYTE *)"test", 4 };
2022 static const struct
2024 const WS_XML_TEXT *text;
2025 const char *result;
2027 tests[] =
2029 { &val_utf8.text, "<t>utf8</t>" },
2030 { &val_utf16.text, "<t>utf16</t>" },
2031 { &val_guid.text, "<t>00000000-0000-0000-0000-000000000000</t>" },
2032 { &val_urn.text, "<t>urn:uuid:00000000-0000-0000-0000-000000000000</t>" },
2033 { &val_bool.text, "<t>true</t>" },
2034 { &val_int32.text, "<t>-2147483648</t>" },
2035 { &val_int64.text, "<t>-9223372036854775808</t>" },
2036 { &val_uint64.text, "<t>18446744073709551615</t>" },
2037 { &val_datetime.text, "<t>0001-01-01T00:00:00Z</t>" },
2038 { &val_double.text, "<t>1.1</t>" },
2039 { &val_base64.text, "<t>dGVzdA==</t>" },
2041 HRESULT hr;
2042 ULONG i;
2044 val_utf16.bytes = (BYTE *)utf16W;
2045 val_utf16.byteCount = sizeof(utf16W);
2047 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2048 ok( hr == S_OK, "got %08x\n", hr );
2050 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
2052 hr = set_output( writer );
2053 ok( hr == S_OK, "got %08x\n", hr );
2054 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2055 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2057 hr = WsWriteText( writer, tests[i].text, NULL );
2058 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2060 hr = WsWriteEndElement( writer, NULL );
2061 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2062 check_output( writer, tests[i].result, __LINE__ );
2065 WsFreeWriter( writer );
2068 static BOOL get_fpword( unsigned short *ret )
2070 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2071 unsigned short fpword;
2072 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
2073 *ret = fpword;
2074 return TRUE;
2075 #endif
2076 return FALSE;
2079 static void set_fpword( unsigned short fpword )
2081 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2082 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2083 #endif
2086 static void test_double(void)
2088 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2089 unsigned short fpword;
2090 static const struct
2092 double val;
2093 const char *result;
2095 tests[] =
2097 {0.0, "<t>0</t>"},
2098 {1.0, "<t>1</t>"},
2099 {-1.0, "<t>-1</t>"},
2100 {1.0000000000000001, "<t>1</t>"},
2101 {1.0000000000000002, "<t>1.0000000000000002</t>"},
2102 {1.0000000000000003, "<t>1.0000000000000002</t>"},
2103 {1.0000000000000004, "<t>1.0000000000000004</t>"},
2104 {100000000000000, "<t>100000000000000</t>"},
2105 {1000000000000000, "<t>1E+15</t>"},
2106 {0.1, "<t>0.1</t>"},
2107 {0.01, "<t>1E-2</t>"},
2108 {-0.1, "<t>-0.1</t>"},
2109 {-0.01, "<t>-1E-2</t>"},
2110 {1.7976931348623158e308, "<t>1.7976931348623157E+308</t>"},
2111 {-1.7976931348623158e308, "<t>-1.7976931348623157E+308</t>"},
2113 HRESULT hr;
2114 WS_XML_WRITER *writer;
2115 WS_XML_DOUBLE_TEXT text;
2116 ULONG i;
2118 hr = WsCreateWriter( NULL, 0, &writer, NULL ) ;
2119 ok( hr == S_OK, "got %08x\n", hr );
2121 text.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
2122 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
2124 hr = set_output( writer );
2125 ok( hr == S_OK, "got %08x\n", hr );
2126 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2127 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2129 text.value = tests[i].val;
2130 hr = WsWriteText( writer, &text.text, NULL );
2131 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2133 hr = WsWriteEndElement( writer, NULL );
2134 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2135 check_output( writer, tests[i].result, __LINE__ );
2138 hr = set_output( writer );
2139 ok( hr == S_OK, "got %08x\n", hr );
2140 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2141 ok( hr == S_OK, "got %08x\n", hr );
2143 text.value = NAN;
2144 hr = WsWriteText( writer, &text.text, NULL );
2145 ok( hr == S_OK, "got %08x\n", hr );
2147 hr = WsWriteEndElement( writer, NULL );
2148 ok( hr == S_OK, "got %08x\n", hr );
2149 check_output( writer, "<t>NaN</t>", __LINE__ );
2151 hr = set_output( writer );
2152 ok( hr == S_OK, "got %08x\n", hr );
2153 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2154 ok( hr == S_OK, "got %08x\n", hr );
2156 text.value = INFINITY;
2157 hr = WsWriteText( writer, &text.text, NULL );
2158 ok( hr == S_OK, "got %08x\n", hr );
2160 hr = WsWriteEndElement( writer, NULL );
2161 ok( hr == S_OK, "got %08x\n", hr );
2162 check_output( writer, "<t>INF</t>", __LINE__ );
2164 hr = set_output( writer );
2165 ok( hr == S_OK, "got %08x\n", hr );
2166 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2167 ok( hr == S_OK, "got %08x\n", hr );
2169 text.value = -INFINITY;
2170 hr = WsWriteText( writer, &text.text, NULL );
2171 ok( hr == S_OK, "got %08x\n", hr );
2173 hr = WsWriteEndElement( writer, NULL );
2174 ok( hr == S_OK, "got %08x\n", hr );
2175 check_output( writer, "<t>-INF</t>", __LINE__ );
2177 if (!get_fpword( &fpword ))
2179 skip( "can't get floating point control word\n" );
2180 WsFreeWriter( writer );
2181 return;
2183 ok( fpword == 0x27f, "got %04x\n", fpword );
2184 set_fpword( 0x1f7f );
2185 get_fpword( &fpword );
2186 ok( fpword == 0x1f7f, "got %04x\n", fpword );
2188 hr = set_output( writer );
2189 ok( hr == S_OK, "got %08x\n", hr );
2190 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2191 ok( hr == S_OK, "got %08x\n", hr );
2193 text.value = 100000000000000;
2194 hr = WsWriteText( writer, &text.text, NULL );
2195 ok( hr == S_OK, "got %08x\n", hr );
2197 hr = WsWriteEndElement( writer, NULL );
2198 ok( hr == S_OK, "got %08x\n", hr );
2199 check_output( writer, "<t>100000000000000</t>", __LINE__ );
2201 get_fpword( &fpword );
2202 ok( fpword == 0x1f7f, "got %04x\n", fpword );
2203 set_fpword( 0x27f );
2205 WsFreeWriter( writer );
2208 static void test_field_options(void)
2210 static const char expected[] =
2211 "<t><bool a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/><int32>-1</int32>"
2212 "<xmlstr a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/></t>";
2213 HRESULT hr;
2214 WS_XML_WRITER *writer;
2215 WS_STRUCT_DESCRIPTION s;
2216 WS_FIELD_DESCRIPTION f, f2, f3, f4, f5, *fields[5];
2217 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, str_guid = {4, (BYTE *)"guid"};
2218 WS_XML_STRING str_int32 = {5, (BYTE *)"int32"}, str_bool = {4, (BYTE *)"bool"};
2219 WS_XML_STRING str_xmlstr = {6, (BYTE *)"xmlstr"}, str_str = {3, (BYTE *)"str"};
2220 INT32 val = -1;
2221 struct test
2223 GUID guid;
2224 BOOL *bool_ptr;
2225 INT32 *int32_ptr;
2226 WS_XML_STRING xmlstr;
2227 WCHAR *str;
2228 } test;
2230 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2231 ok( hr == S_OK, "got %08x\n", hr );
2233 hr = set_output( writer );
2234 ok( hr == S_OK, "got %08x\n", hr );
2236 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2237 ok( hr == S_OK, "got %08x\n", hr );
2239 memset( &f, 0, sizeof(f) );
2240 f.mapping = WS_ELEMENT_FIELD_MAPPING;
2241 f.localName = &str_guid;
2242 f.ns = &ns;
2243 f.type = WS_GUID_TYPE;
2244 f.options = WS_FIELD_OPTIONAL;
2245 fields[0] = &f;
2247 memset( &f2, 0, sizeof(f2) );
2248 f2.mapping = WS_ELEMENT_FIELD_MAPPING;
2249 f2.localName = &str_bool;
2250 f2.offset = FIELD_OFFSET(struct test, bool_ptr);
2251 f2.ns = &ns;
2252 f2.type = WS_BOOL_TYPE;
2253 f2.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2254 fields[1] = &f2;
2256 memset( &f3, 0, sizeof(f3) );
2257 f3.mapping = WS_ELEMENT_FIELD_MAPPING;
2258 f3.localName = &str_int32;
2259 f3.offset = FIELD_OFFSET(struct test, int32_ptr);
2260 f3.ns = &ns;
2261 f3.type = WS_INT32_TYPE;
2262 f3.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2263 fields[2] = &f3;
2265 memset( &f4, 0, sizeof(f4) );
2266 f4.mapping = WS_ELEMENT_FIELD_MAPPING;
2267 f4.localName = &str_xmlstr;
2268 f4.offset = FIELD_OFFSET(struct test, xmlstr);
2269 f4.ns = &ns;
2270 f4.type = WS_XML_STRING_TYPE;
2271 f4.options = WS_FIELD_NILLABLE;
2272 fields[3] = &f4;
2274 memset( &f5, 0, sizeof(f5) );
2275 f5.mapping = WS_ELEMENT_FIELD_MAPPING;
2276 f5.localName = &str_str;
2277 f5.offset = FIELD_OFFSET(struct test, str);
2278 f5.ns = &ns;
2279 f5.type = WS_WSZ_TYPE;
2280 f5.options = WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE;
2281 fields[4] = &f5;
2283 memset( &s, 0, sizeof(s) );
2284 s.size = sizeof(struct test);
2285 s.alignment = TYPE_ALIGNMENT(struct test);
2286 s.fields = fields;
2287 s.fieldCount = 5;
2289 memset( &test, 0, sizeof(test) );
2290 test.int32_ptr = &val;
2291 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
2292 &test, sizeof(test), NULL );
2293 ok( hr == S_OK, "got %08x\n", hr );
2295 hr = WsWriteEndElement( writer, NULL );
2296 ok( hr == S_OK, "got %08x\n", hr );
2297 check_output( writer, expected, __LINE__ );
2299 WsFreeWriter( writer );
2302 static void test_WsWriteText(void)
2304 static const WCHAR testW[] = {'t','e','s','t'};
2305 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
2306 HRESULT hr;
2307 WS_XML_WRITER *writer;
2308 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2309 WS_XML_UTF16_TEXT utf16 = {{WS_XML_TEXT_TYPE_UTF16}};
2310 WS_XML_GUID_TEXT guid = {{WS_XML_TEXT_TYPE_GUID}};
2312 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2313 ok( hr == S_OK, "got %08x\n", hr );
2315 hr = set_output( writer );
2316 ok( hr == S_OK, "got %08x\n", hr );
2318 utf8.value.bytes = (BYTE *)"test";
2319 utf8.value.length = 4;
2320 hr = WsWriteText( writer, &utf8.text, NULL );
2321 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
2323 hr = set_output( writer );
2324 ok( hr == S_OK, "got %08x\n", hr );
2326 /* element, utf8 */
2327 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2328 ok( hr == S_OK, "got %08x\n", hr );
2330 hr = WsWriteText( writer, &utf8.text, NULL );
2331 ok( hr == S_OK, "got %08x\n", hr );
2332 check_output( writer, "<t>test", __LINE__ );
2334 utf8.value.bytes = (BYTE *)"tset";
2335 hr = WsWriteText( writer, &utf8.text, NULL );
2336 ok( hr == S_OK, "got %08x\n", hr );
2337 check_output( writer, "<t>testtset", __LINE__ );
2339 hr = WsWriteEndElement( writer, NULL );
2340 ok( hr == S_OK, "got %08x\n", hr );
2341 check_output( writer, "<t>testtset</t>", __LINE__ );
2343 hr = set_output( writer );
2344 ok( hr == S_OK, "got %08x\n", hr );
2346 /* attribute, utf8 */
2347 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2348 ok( hr == S_OK, "got %08x\n", hr );
2350 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2351 ok( hr == S_OK, "got %08x\n", hr );
2353 hr = WsWriteText( writer, &utf8.text, NULL );
2354 ok( hr == S_OK, "got %08x\n", hr );
2355 check_output( writer, "", __LINE__ );
2357 utf8.value.bytes = (BYTE *)"test";
2358 hr = WsWriteText( writer, &utf8.text, NULL );
2359 ok( hr == S_OK, "got %08x\n", hr );
2360 check_output( writer, "", __LINE__ );
2362 hr = WsWriteEndAttribute( writer, NULL );
2363 ok( hr == S_OK, "got %08x\n", hr );
2365 hr = WsWriteEndElement( writer, NULL );
2366 ok( hr == S_OK, "got %08x\n", hr );
2367 check_output( writer, "<t a=\"tsettest\"/>", __LINE__ );
2369 hr = set_output( writer );
2370 ok( hr == S_OK, "got %08x\n", hr );
2372 /* element, utf16 */
2373 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2374 ok( hr == S_OK, "got %08x\n", hr );
2376 utf16.bytes = (BYTE *)testW;
2377 utf16.byteCount = sizeof(testW);
2378 hr = WsWriteText( writer, &utf16.text, NULL );
2379 ok( hr == S_OK, "got %08x\n", hr );
2380 check_output( writer, "<t>test", __LINE__ );
2382 hr = WsWriteText( writer, &utf16.text, NULL );
2383 ok( hr == S_OK, "got %08x\n", hr );
2384 check_output( writer, "<t>testtest", __LINE__ );
2386 hr = WsWriteEndElement( writer, NULL );
2387 ok( hr == S_OK, "got %08x\n", hr );
2388 check_output( writer, "<t>testtest</t>", __LINE__ );
2390 hr = set_output( writer );
2391 ok( hr == S_OK, "got %08x\n", hr );
2393 /* attribute, utf16 */
2394 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2395 ok( hr == S_OK, "got %08x\n", hr );
2397 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2398 ok( hr == S_OK, "got %08x\n", hr );
2400 hr = WsWriteText( writer, &utf16.text, NULL );
2401 ok( hr == S_OK, "got %08x\n", hr );
2402 check_output( writer, "", __LINE__ );
2404 hr = WsWriteText( writer, &utf16.text, NULL );
2405 ok( hr == S_OK, "got %08x\n", hr );
2406 check_output( writer, "", __LINE__ );
2408 hr = WsWriteEndAttribute( writer, NULL );
2409 ok( hr == S_OK, "got %08x\n", hr );
2411 hr = WsWriteEndElement( writer, NULL );
2412 ok( hr == S_OK, "got %08x\n", hr );
2413 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
2415 hr = set_output( writer );
2416 ok( hr == S_OK, "got %08x\n", hr );
2418 /* element, guid */
2419 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2420 ok( hr == S_OK, "got %08x\n", hr );
2422 hr = WsWriteText( writer, &guid.text, NULL );
2423 ok( hr == S_OK, "got %08x\n", hr );
2424 check_output( writer, "<t>00000000-0000-0000-0000-000000000000", __LINE__ );
2426 hr = WsWriteText( writer, &guid.text, NULL );
2427 ok( hr == S_OK, "got %08x\n", hr );
2428 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000",
2429 __LINE__ );
2431 /* continue with different text type */
2432 hr = WsWriteText( writer, &utf8.text, NULL );
2433 ok( hr == S_OK, "got %08x\n", hr );
2434 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000test",
2435 __LINE__ );
2437 hr = WsWriteEndElement( writer, NULL );
2438 ok( hr == S_OK, "got %08x\n", hr );
2440 hr = set_output( writer );
2441 ok( hr == S_OK, "got %08x\n", hr );
2443 /* attribute, guid */
2444 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2445 ok( hr == S_OK, "got %08x\n", hr );
2447 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2448 ok( hr == S_OK, "got %08x\n", hr );
2450 hr = WsWriteText( writer, &guid.text, NULL );
2451 ok( hr == S_OK, "got %08x\n", hr );
2452 check_output( writer, "", __LINE__ );
2454 hr = WsWriteText( writer, &guid.text, NULL );
2455 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2457 hr = set_output( writer );
2458 ok( hr == S_OK, "got %08x\n", hr );
2460 /* attribute, mix allowed text types */
2461 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2462 ok( hr == S_OK, "got %08x\n", hr );
2464 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2465 ok( hr == S_OK, "got %08x\n", hr );
2467 hr = WsWriteText( writer, &utf8.text, NULL );
2468 ok( hr == S_OK, "got %08x\n", hr );
2470 hr = WsWriteText( writer, &utf16.text, NULL );
2471 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2473 hr = set_output( writer );
2474 ok( hr == S_OK, "got %08x\n", hr );
2476 /* cdata */
2477 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2478 ok( hr == S_OK, "got %08x\n", hr );
2479 hr = WsWriteStartCData( writer, NULL );
2480 ok( hr == S_OK, "got %08x\n", hr );
2482 hr = WsWriteText( writer, &utf8.text, NULL );
2483 ok( hr == S_OK, "got %08x\n", hr );
2485 hr = WsWriteText( writer, &guid.text, NULL );
2486 ok( hr == S_OK, "got %08x\n", hr );
2488 hr = WsWriteEndCData( writer, NULL );
2489 ok( hr == S_OK, "got %08x\n", hr );
2490 hr = WsWriteEndElement( writer, NULL );
2491 ok( hr == S_OK, "got %08x\n", hr );
2492 check_output( writer, "<t><![CDATA[test00000000-0000-0000-0000-000000000000]]></t>", __LINE__ );
2494 WsFreeWriter( writer );
2497 static void test_WsWriteArray(void)
2499 static const WS_XML_STRING localname = {4, (BYTE *)"item"}, localname2 = {5, (BYTE *)"array"};
2500 static const WS_XML_STRING ns = {0, NULL};
2501 WS_XML_WRITER *writer;
2502 BOOL array_bool[2];
2503 HRESULT hr;
2505 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2506 ok( hr == S_OK, "got %08x\n", hr );
2508 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2509 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2511 hr = set_output( writer );
2512 ok( hr == S_OK, "got %08x\n", hr );
2513 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2514 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2516 hr = set_output( writer );
2517 ok( hr == S_OK, "got %08x\n", hr );
2518 hr = WsWriteArray( writer, &localname, NULL, 0, NULL, 0, 0, 0, NULL );
2519 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2521 hr = set_output( writer );
2522 ok( hr == S_OK, "got %08x\n", hr );
2523 hr = WsWriteArray( writer, &localname, &ns, 0, NULL, 0, 0, 0, NULL );
2524 ok( hr == S_OK, "got %08x\n", hr );
2525 check_output( writer, "", __LINE__ );
2527 hr = WsWriteArray( writer, &localname, &ns, ~0u, NULL, 0, 0, 0, NULL );
2528 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2530 hr = set_output( writer );
2531 ok( hr == S_OK, "got %08x\n", hr );
2532 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, 0, 0, 0, NULL );
2533 ok( hr == S_OK, "got %08x\n", hr );
2534 check_output( writer, "", __LINE__ );
2536 array_bool[0] = FALSE;
2537 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, 0, 0, 0, NULL );
2538 ok( hr == S_OK, "got %08x\n", hr );
2539 check_output( writer, "", __LINE__ );
2541 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 0, NULL );
2542 ok( hr == S_OK, "got %08x\n", hr );
2543 check_output( writer, "", __LINE__ );
2545 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 0, NULL );
2546 ok( hr == S_OK, "got %08x\n", hr );
2547 check_output( writer, "", __LINE__ );
2549 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 1, NULL );
2550 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2552 hr = set_output( writer );
2553 ok( hr == S_OK, "got %08x\n", hr );
2554 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 1, NULL );
2555 ok( hr == S_OK, "got %08x\n", hr );
2556 check_output( writer, "<item>false</item>", __LINE__ );
2558 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool) - 1, 0, 2, NULL );
2559 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2561 hr = set_output( writer );
2562 ok( hr == S_OK, "got %08x\n", hr );
2563 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 3, NULL );
2564 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2566 hr = set_output( writer );
2567 ok( hr == S_OK, "got %08x\n", hr );
2569 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
2570 ok( hr == S_OK, "got %08x\n", hr );
2572 array_bool[1] = TRUE;
2573 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 2, NULL );
2574 ok( hr == S_OK, "got %08x\n", hr );
2576 hr = WsWriteEndElement( writer, NULL );
2577 ok( hr == S_OK, "got %08x\n", hr );
2578 check_output( writer, "<array><item>false</item><item>true</item></array>", __LINE__ );
2580 WsFreeWriter( writer );
2583 static void test_escapes(void)
2585 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2586 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2587 WS_XML_WRITER *writer;
2588 struct test
2590 const char *text;
2591 const char *result;
2592 BOOL single;
2594 static const struct test tests_elem[] =
2596 { "<", "<t>&lt;</t>" },
2597 { ">", "<t>&gt;</t>" },
2598 { "\"", "<t>\"</t>" },
2599 { "&", "<t>&amp;</t>" },
2600 { "&&", "<t>&amp;&amp;</t>" },
2601 { "'", "<t>'</t>" },
2603 static const struct test tests_attr[] =
2605 { "<", "<t t=\"&lt;\"/>" },
2606 { ">", "<t t=\">\"/>" },
2607 { "\"", "<t t=\"&quot;\"/>" },
2608 { "&", "<t t=\"&amp;\"/>" },
2609 { "'", "<t t=\"'\"/>" },
2610 { "\"", "<t t='\"'/>", TRUE },
2611 { "'", "<t t='&apos;'/>", TRUE },
2613 static const struct test tests_cdata[] =
2615 { "<", "<t><![CDATA[<]]></t>" },
2616 { ">", "<t><![CDATA[>]]></t>" },
2617 { "\"", "<t><![CDATA[\"]]></t>" },
2618 { "&", "<t><![CDATA[&]]></t>" },
2619 { "[", "<t><![CDATA[[]]></t>" },
2620 { "]", "<t><![CDATA[]]]></t>" },
2621 { "'", "<t><![CDATA[']]></t>" },
2623 static const struct test tests_comment[] =
2625 { "<", "<t><!--<--></t>" },
2626 { ">", "<t><!-->--></t>" },
2627 { "\"", "<t><!--\"--></t>" },
2628 { "&", "<t><!--&--></t>" },
2629 { "'", "<t><!--'--></t>" },
2631 HRESULT hr;
2632 ULONG i;
2634 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2635 ok( hr == S_OK, "got %08x\n", hr );
2637 for (i = 0; i < sizeof(tests_elem)/sizeof(tests_elem[0]); i++)
2639 hr = set_output( writer );
2640 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2641 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2642 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2644 utf8.value.bytes = (BYTE *)tests_elem[i].text;
2645 utf8.value.length = strlen( tests_elem[i].text );
2646 hr = WsWriteText( writer, &utf8.text, NULL );
2647 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2649 hr = WsWriteEndElement( writer, NULL );
2650 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2651 check_output( writer, tests_elem[i].result, __LINE__ );
2654 for (i = 0; i < sizeof(tests_attr)/sizeof(tests_attr[0]); i++)
2656 hr = set_output( writer );
2657 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2658 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2659 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2661 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, tests_attr[i].single, NULL );
2662 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2664 utf8.value.bytes = (BYTE *)tests_attr[i].text;
2665 utf8.value.length = strlen( tests_attr[i].text );
2666 hr = WsWriteText( writer, &utf8.text, NULL );
2667 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2669 hr = WsWriteEndAttribute( writer, NULL );
2670 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2672 hr = WsWriteEndElement( writer, NULL );
2673 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2674 check_output( writer, tests_attr[i].result, __LINE__ );
2677 for (i = 0; i < sizeof(tests_cdata)/sizeof(tests_cdata[0]); i++)
2679 hr = set_output( writer );
2680 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2681 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2682 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2684 hr = WsWriteStartCData( writer, NULL );
2685 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2687 utf8.value.bytes = (BYTE *)tests_cdata[i].text;
2688 utf8.value.length = strlen( tests_cdata[i].text );
2689 hr = WsWriteText( writer, &utf8.text, NULL );
2690 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2692 hr = WsWriteEndCData( writer, NULL );
2693 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2695 hr = WsWriteEndElement( writer, NULL );
2696 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2697 check_output( writer, tests_cdata[i].result, __LINE__ );
2700 for (i = 0; i < sizeof(tests_comment)/sizeof(tests_comment[0]); i++)
2702 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
2704 hr = set_output( writer );
2705 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2706 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2707 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2709 comment.value.bytes = (BYTE *)tests_comment[i].text;
2710 comment.value.length = strlen( tests_comment[i].text );
2711 hr = WsWriteNode( writer, &comment.node, NULL );
2712 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2714 hr = WsWriteEndElement( writer, NULL );
2715 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2716 check_output( writer, tests_comment[i].result, __LINE__ );
2719 WsFreeWriter( writer );
2722 static void test_write_option(void)
2724 static const WCHAR sW[] = {'s',0};
2725 static const WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2726 WS_XML_WRITER *writer;
2727 int val_int = -1, val_int_zero = 0, *ptr_int = &val_int, *ptr_int_null = NULL;
2728 const WCHAR *ptr_wsz = sW, *ptr_wsz_null = NULL;
2729 static const WS_XML_STRING val_xmlstr = {1, (BYTE *)"x"}, val_xmlstr_zero = {0, NULL};
2730 const WS_XML_STRING *ptr_xmlstr = &val_xmlstr, *ptr_xmlstr_null = NULL;
2731 struct
2733 WS_TYPE type;
2734 WS_WRITE_OPTION option;
2735 const void *value;
2736 ULONG size;
2737 HRESULT hr;
2738 const char *result;
2740 tests[] =
2742 { WS_INT32_TYPE, 0, NULL, 0, E_INVALIDARG },
2743 { WS_INT32_TYPE, 0, "str", 0, E_INVALIDARG },
2744 { WS_INT32_TYPE, 0, NULL, sizeof(val_int), E_INVALIDARG },
2745 { WS_INT32_TYPE, 0, &val_int, sizeof(val_int), E_INVALIDARG },
2746 { WS_INT32_TYPE, 0, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2747 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2748 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, 0, E_INVALIDARG },
2749 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2750 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, sizeof(val_int), S_OK, "<t>-1</t>" },
2751 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int_zero, sizeof(val_int_zero), S_OK, "<t>0</t>" },
2752 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, 0, E_INVALIDARG },
2753 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, 0, E_INVALIDARG },
2754 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2755 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, sizeof(val_int), E_INVALIDARG },
2756 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2757 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2758 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, 0, E_INVALIDARG },
2759 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2760 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2761 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int_null, sizeof(ptr_int_null), E_INVALIDARG },
2762 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2763 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, 0, E_INVALIDARG },
2764 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2765 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2766 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int_null, sizeof(ptr_int_null), S_OK,
2767 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2768 { WS_XML_STRING_TYPE, 0, NULL, 0, E_INVALIDARG },
2769 { WS_XML_STRING_TYPE, 0, &val_xmlstr, 0, E_INVALIDARG },
2770 { WS_XML_STRING_TYPE, 0, NULL, sizeof(val_xmlstr), E_INVALIDARG },
2771 { WS_XML_STRING_TYPE, 0, &val_xmlstr, sizeof(val_xmlstr), E_INVALIDARG },
2772 { WS_XML_STRING_TYPE, 0, &val_xmlstr_zero, sizeof(val_xmlstr_zero), E_INVALIDARG },
2773 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2774 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2775 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2776 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, sizeof(val_xmlstr), S_OK, "<t>x</t>" },
2777 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, "<t/>" },
2778 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2779 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2780 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, sizeof(&val_xmlstr), E_INVALIDARG },
2781 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK,
2782 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2783 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2784 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2785 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2786 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2787 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), E_INVALIDARG },
2788 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2789 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2790 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2791 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2792 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), S_OK,
2793 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2794 { WS_WSZ_TYPE, 0, NULL, 0, E_INVALIDARG },
2795 { WS_WSZ_TYPE, 0, &ptr_wsz, 0, E_INVALIDARG },
2796 { WS_WSZ_TYPE, 0, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2797 { WS_WSZ_TYPE, 0, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2798 { WS_WSZ_TYPE, 0, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2799 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2800 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2801 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2802 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2803 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2804 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2805 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2806 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2807 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2808 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2809 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2810 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), S_OK,
2811 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2813 HRESULT hr;
2814 ULONG i;
2816 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2817 ok( hr == S_OK, "got %08x\n", hr );
2819 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
2821 hr = set_output( writer );
2822 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2823 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2824 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL, tests[i].option, tests[i].value,
2825 tests[i].size, NULL );
2826 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
2827 WsWriteEndElement( writer, NULL );
2828 if (hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
2831 WsFreeWriter( writer );
2834 static BOOL check_result( WS_XML_WRITER *writer, const char *expected )
2836 WS_BYTES bytes;
2837 ULONG size = sizeof(bytes);
2838 int len = strlen( expected );
2840 memset( &bytes, 0, sizeof(bytes) );
2841 WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
2842 if (bytes.length != len) return FALSE;
2843 return !memcmp( bytes.bytes, expected, len );
2846 static void test_datetime(void)
2848 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2849 static const struct
2851 unsigned __int64 ticks;
2852 WS_DATETIME_FORMAT format;
2853 HRESULT hr;
2854 const char *result;
2855 const char *result2;
2856 HRESULT hr_broken;
2858 tests[] =
2860 { 0, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00Z</t>" },
2861 { 0, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00+00:00</t>" },
2862 { 0, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00</t>" },
2863 { 1, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00.0000001Z</t>" },
2864 { 1, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00.0000001+00:00</t>" },
2865 { 1, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.0000001</t>" },
2866 { 10, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.000001</t>" },
2867 { 1000000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.1</t>" },
2868 { 0x23c34600, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:01:00+00:00</t>" },
2869 { 0x861c46800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T01:00:00+00:00</t>" },
2870 { 0x430e234000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T08:00:00+00:00</t>" },
2871 { 0x4b6fe7a800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T09:00:00+00:00</t>" },
2872 { 0x989680, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:01</t>" },
2873 { 0x23c34600, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:01:00</t>" },
2874 { 0x861c46800, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T01:00:00</t>" },
2875 { 0xc92a69c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-02T00:00:00</t>" },
2876 { 0x11ed178c6c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0002-01-01T00:00:00</t>" },
2877 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_UTC, S_OK, "<t>9999-12-31T23:59:59.9999999Z</t>" },
2878 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>9999-12-31T15:59:59.9999999-08:00</t>",
2879 "<t>9999-12-31T17:59:59.9999999-06:00</t>" /* win7 */, WS_E_INVALID_FORMAT },
2880 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_NONE, S_OK, "<t>9999-12-31T23:59:59.9999999</t>" },
2881 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_UTC, WS_E_INVALID_FORMAT },
2882 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_LOCAL, WS_E_INVALID_FORMAT },
2883 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_NONE, WS_E_INVALID_FORMAT },
2884 { 0x8d3123e7df74000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>2015-12-31T16:00:00-08:00</t>",
2885 "<t>2015-12-31T18:00:00-06:00</t>" /* win7 */ },
2886 { 0x701ce1722770000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00+00:00</t>" },
2887 { 0x701ce5a309a4000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00-08:00</t>",
2888 "<t>1601-01-01T02:00:00-06:00</t>" /* win7 */ },
2889 { 0x701ce5e617c7400, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:30:00-08:00</t>",
2890 "<t>1601-01-01T02:30:00-06:00</t>" /* win7 */ },
2891 { 0x701ce51ced5d800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T07:00:00+00:00</t>",
2892 "<t>1601-01-01T01:00:00-06:00</t>" /* win7 */ },
2893 { 0, WS_DATETIME_FORMAT_NONE + 1, WS_E_INVALID_FORMAT },
2894 { 0x38a080649c000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-28T00:00:00Z</t>" },
2895 { 0x38ad130b38000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-29T00:00:00Z</t>" },
2896 { 0x8c1505f0e438000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2000-02-29T00:00:00Z</t>" },
2897 { 0x8d46035e7870000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2017-03-01T00:00:00Z</t>" },
2899 HRESULT hr;
2900 WS_XML_WRITER *writer;
2901 WS_DATETIME date;
2902 ULONG i;
2904 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2905 ok( hr == S_OK, "got %08x\n", hr );
2906 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
2908 hr = set_output( writer );
2909 ok( hr == S_OK, "got %08x\n", hr );
2911 date.ticks = tests[i].ticks;
2912 date.format = tests[i].format;
2913 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2914 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_DATETIME_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
2915 &date, sizeof(date), NULL );
2916 WsWriteEndElement( writer, NULL );
2917 ok( hr == tests[i].hr || broken(hr == tests[i].hr_broken), "%u: got %08x\n", i, hr );
2918 if (hr != tests[i].hr && hr == tests[i].hr_broken) break;
2919 if (hr == S_OK)
2921 ok( check_result( writer, tests[i].result ) ||
2922 (tests[i].result2 && broken(check_result( writer, tests[i].result2 ))),
2923 "%u: wrong result\n", i );
2927 WsFreeWriter( writer );
2930 static void test_repeating_element(void)
2932 static const WCHAR oneW[] = {'1',0}, twoW[] = {'2',0};
2933 WS_XML_STRING localname = {4, (BYTE *)"test"}, ns = {0, NULL};
2934 WS_XML_STRING val = {3, (BYTE *)"val"}, wrapper = {7, (BYTE *)"wrapper"};
2935 HRESULT hr;
2936 WS_XML_WRITER *writer;
2937 WS_STRUCT_DESCRIPTION s;
2938 WS_FIELD_DESCRIPTION f, *fields[1];
2939 WS_ITEM_RANGE range;
2940 struct test
2942 const WCHAR **val;
2943 ULONG count;
2944 } *test;
2945 struct test2
2947 INT32 *val;
2948 ULONG count;
2949 } *test2;
2951 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2952 ok( hr == S_OK, "got %08x\n", hr );
2954 /* array of strings, wrapper */
2955 hr = set_output( writer );
2956 ok( hr == S_OK, "got %08x\n", hr );
2957 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2958 ok( hr == S_OK, "got %08x\n", hr );
2960 memset( &f, 0, sizeof(f) );
2961 f.mapping = WS_REPEATING_ELEMENT_FIELD_MAPPING;
2962 f.localName = &wrapper;
2963 f.ns = &ns;
2964 f.type = WS_WSZ_TYPE;
2965 f.countOffset = FIELD_OFFSET(struct test, count);
2966 f.itemLocalName = &val;
2967 f.itemNs = &ns;
2968 fields[0] = &f;
2970 memset( &s, 0, sizeof(s) );
2971 s.size = sizeof(struct test);
2972 s.alignment = TYPE_ALIGNMENT(struct test);
2973 s.typeLocalName = &localname;
2974 s.typeNs = &ns;
2975 s.fields = fields;
2976 s.fieldCount = 1;
2978 hr = set_output( writer );
2979 ok( hr == S_OK, "got %08x\n", hr );
2980 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2981 ok( hr == S_OK, "got %08x\n", hr );
2983 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) + 2 * sizeof(const WCHAR *) );
2984 test->val = (const WCHAR **)(test + 1);
2985 test->val[0] = oneW;
2986 test->val[1] = twoW;
2987 test->count = 2;
2988 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
2989 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
2990 ok( hr == S_OK, "got %08x\n", hr );
2991 hr = WsWriteEndElement( writer, NULL );
2992 ok( hr == S_OK, "got %08x\n", hr );
2993 check_output( writer, "<test><wrapper><val>1</val><val>2</val></wrapper></test>", __LINE__ );
2994 HeapFree( GetProcessHeap(), 0, test );
2996 /* array of integers, no wrapper */
2997 hr = set_output( writer );
2998 ok( hr == S_OK, "got %08x\n", hr );
2999 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3000 ok( hr == S_OK, "got %08x\n", hr );
3002 f.type = WS_INT32_TYPE;
3003 f.localName = NULL;
3004 f.ns = NULL;
3006 test2 = HeapAlloc( GetProcessHeap(), 0, sizeof(*test2) + 2 * sizeof(INT32) );
3007 test2->val = (INT32 *)(test2 + 1);
3008 test2->val[0] = 1;
3009 test2->val[1] = 2;
3010 test2->count = 2;
3011 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3012 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3013 ok( hr == S_OK, "got %08x\n", hr );
3014 hr = WsWriteEndElement( writer, NULL );
3015 ok( hr == S_OK, "got %08x\n", hr );
3016 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3018 /* item range has no effect */
3019 hr = set_output( writer );
3020 ok( hr == S_OK, "got %08x\n", hr );
3021 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3022 ok( hr == S_OK, "got %08x\n", hr );
3024 range.minItemCount = 0;
3025 range.maxItemCount = 0;
3026 f.itemRange = &range;
3028 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3029 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3030 ok( hr == S_OK, "got %08x\n", hr );
3031 hr = WsWriteEndElement( writer, NULL );
3032 ok( hr == S_OK, "got %08x\n", hr );
3033 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3034 HeapFree( GetProcessHeap(), 0, test2 );
3036 WsFreeWriter( writer );
3039 static const WS_XML_STRING *init_xmlstring( const char *src, WS_XML_STRING *str )
3041 if (!src) return NULL;
3042 str->length = strlen( src );
3043 str->bytes = (BYTE *)src;
3044 return str;
3047 static void test_WsWriteQualifiedName(void)
3049 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
3050 WS_XML_WRITER *writer;
3051 HRESULT hr;
3052 ULONG i;
3053 static const struct
3055 const char *prefix;
3056 const char *localname;
3057 const char *ns;
3058 HRESULT hr;
3059 const char *result;
3060 } tests[] =
3062 { NULL, NULL, NULL, E_INVALIDARG, NULL },
3063 { NULL, "t2", NULL, E_INVALIDARG, NULL },
3064 { "p2", "t2", NULL, S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3065 { NULL, "t2", "ns2", WS_E_INVALID_FORMAT, NULL },
3066 { NULL, "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t2" },
3067 { "p2", "t2", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3068 { "p2", "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3069 { "p", "t", NULL, S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3070 { NULL, "t", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3071 { "p2", "", "", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3072 { "p2", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3073 { "p2", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3074 { "", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">t2" },
3075 { "", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">" },
3076 { "", "", "", S_OK, "<p:t xmlns:p=\"ns\">" },
3079 hr = WsWriteQualifiedName( NULL, NULL, NULL, NULL, NULL );
3080 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3082 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3083 ok( hr == S_OK, "got %08x\n", hr );
3085 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3086 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3088 hr = set_output( writer );
3089 ok( hr == S_OK, "got %08x\n", hr );
3091 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3092 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3094 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
3096 WS_XML_STRING prefix2, localname2, ns2;
3097 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3099 hr = set_output( writer );
3100 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3102 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
3103 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3105 prefix_ptr = init_xmlstring( tests[i].prefix, &prefix2 );
3106 localname_ptr = init_xmlstring( tests[i].localname, &localname2 );
3107 ns_ptr = init_xmlstring( tests[i].ns, &ns2 );
3109 hr = WsWriteQualifiedName( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3110 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
3111 if (tests[i].hr == S_OK && hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
3114 WsFreeWriter( writer );
3117 static void test_WsWriteBytes(void)
3119 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3120 WS_XML_WRITER *writer;
3121 HRESULT hr;
3123 hr = WsWriteBytes( NULL, NULL, 0, NULL );
3124 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3126 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3127 ok( hr == S_OK, "got %08x\n", hr );
3129 hr = WsWriteBytes( writer, NULL, 0, NULL );
3130 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3132 hr = WsWriteBytes( writer, "test", 0, NULL );
3133 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3135 hr = WsWriteBytes( writer, NULL, 1, NULL );
3136 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3138 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3139 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3141 hr = set_output( writer );
3142 ok( hr == S_OK, "got %08x\n", hr );
3144 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3145 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3147 hr = set_output( writer );
3148 ok( hr == S_OK, "got %08x\n", hr );
3150 /* element */
3151 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3152 ok( hr == S_OK, "got %08x\n", hr );
3154 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3155 ok( hr == S_OK, "got %08x\n", hr );
3157 hr = WsWriteEndElement( writer, NULL );
3158 ok( hr == S_OK, "got %08x\n", hr );
3159 check_output( writer, "<t>dGVzdAA=</t>", __LINE__ );
3161 hr = set_output( writer );
3162 ok( hr == S_OK, "got %08x\n", hr );
3164 /* attribute */
3165 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3166 ok( hr == S_OK, "got %08x\n", hr );
3168 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3169 ok( hr == S_OK, "got %08x\n", hr );
3171 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3172 ok( hr == S_OK, "got %08x\n", hr );
3174 hr = WsWriteEndAttribute( writer, NULL );
3175 ok( hr == S_OK, "got %08x\n", hr );
3177 hr = WsWriteEndElement( writer, NULL );
3178 ok( hr == S_OK, "got %08x\n", hr );
3179 check_output( writer, "<t a=\"dGVzdAA=\"/>", __LINE__ );
3181 WsFreeWriter( writer );
3184 static void test_WsWriteChars(void)
3186 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3187 static const WCHAR testW[] = {'t','e','s','t'};
3188 WS_XML_WRITER *writer;
3189 HRESULT hr;
3191 hr = WsWriteChars( NULL, NULL, 0, NULL );
3192 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3194 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3195 ok( hr == S_OK, "got %08x\n", hr );
3197 hr = WsWriteChars( writer, NULL, 0, NULL );
3198 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3200 hr = WsWriteChars( writer, testW, 0, NULL );
3201 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3203 hr = WsWriteChars( writer, NULL, 1, NULL );
3204 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3206 hr = WsWriteChars( writer, testW, 4, NULL );
3207 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3209 hr = set_output( writer );
3210 ok( hr == S_OK, "got %08x\n", hr );
3212 hr = WsWriteChars( writer, testW, 4, NULL );
3213 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3215 hr = set_output( writer );
3216 ok( hr == S_OK, "got %08x\n", hr );
3218 /* element */
3219 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3220 ok( hr == S_OK, "got %08x\n", hr );
3222 hr = WsWriteChars( writer, testW, 4, NULL );
3223 ok( hr == S_OK, "got %08x\n", hr );
3225 hr = WsWriteChars( writer, testW, 4, NULL );
3226 ok( hr == S_OK, "got %08x\n", hr );
3228 hr = WsWriteEndElement( writer, NULL );
3229 ok( hr == S_OK, "got %08x\n", hr );
3230 check_output( writer, "<t>testtest</t>", __LINE__ );
3232 hr = set_output( writer );
3233 ok( hr == S_OK, "got %08x\n", hr );
3235 /* attribute */
3236 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3237 ok( hr == S_OK, "got %08x\n", hr );
3239 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3240 ok( hr == S_OK, "got %08x\n", hr );
3242 hr = WsWriteChars( writer, testW, 4, NULL );
3243 ok( hr == S_OK, "got %08x\n", hr );
3245 hr = WsWriteChars( writer, testW, 4, NULL );
3246 ok( hr == S_OK, "got %08x\n", hr );
3248 hr = WsWriteEndAttribute( writer, NULL );
3249 ok( hr == S_OK, "got %08x\n", hr );
3251 hr = WsWriteEndElement( writer, NULL );
3252 ok( hr == S_OK, "got %08x\n", hr );
3253 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3255 WsFreeWriter( writer );
3258 static void test_WsWriteCharsUtf8(void)
3260 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3261 static const BYTE test[] = {'t','e','s','t'};
3262 WS_XML_WRITER *writer;
3263 HRESULT hr;
3265 hr = WsWriteCharsUtf8( NULL, NULL, 0, NULL );
3266 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3268 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3269 ok( hr == S_OK, "got %08x\n", hr );
3271 hr = WsWriteCharsUtf8( writer, NULL, 0, NULL );
3272 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3274 hr = WsWriteCharsUtf8( writer, test, 0, NULL );
3275 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3277 hr = WsWriteCharsUtf8( writer, NULL, 1, NULL );
3278 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3280 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3281 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3283 hr = set_output( writer );
3284 ok( hr == S_OK, "got %08x\n", hr );
3286 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3287 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3289 hr = set_output( writer );
3290 ok( hr == S_OK, "got %08x\n", hr );
3292 /* element */
3293 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3294 ok( hr == S_OK, "got %08x\n", hr );
3296 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3297 ok( hr == S_OK, "got %08x\n", hr );
3299 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3300 ok( hr == S_OK, "got %08x\n", hr );
3302 hr = WsWriteEndElement( writer, NULL );
3303 ok( hr == S_OK, "got %08x\n", hr );
3304 check_output( writer, "<t>testtest</t>", __LINE__ );
3306 hr = set_output( writer );
3307 ok( hr == S_OK, "got %08x\n", hr );
3309 /* attribute */
3310 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3311 ok( hr == S_OK, "got %08x\n", hr );
3313 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3314 ok( hr == S_OK, "got %08x\n", hr );
3316 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3317 ok( hr == S_OK, "got %08x\n", hr );
3319 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3320 ok( hr == S_OK, "got %08x\n", hr );
3322 hr = WsWriteEndAttribute( writer, NULL );
3323 ok( hr == S_OK, "got %08x\n", hr );
3325 hr = WsWriteEndElement( writer, NULL );
3326 ok( hr == S_OK, "got %08x\n", hr );
3327 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3329 WsFreeWriter( writer );
3332 START_TEST(writer)
3334 test_WsCreateWriter();
3335 test_WsCreateXmlBuffer();
3336 test_WsSetOutput();
3337 test_WsSetOutputToBuffer();
3338 test_WsWriteStartElement();
3339 test_WsWriteStartAttribute();
3340 test_WsWriteType();
3341 test_basic_type();
3342 test_simple_struct_type();
3343 test_WsWriteElement();
3344 test_WsWriteValue();
3345 test_WsWriteAttribute();
3346 test_WsWriteStartCData();
3347 test_WsWriteXmlnsAttribute();
3348 test_WsGetPrefixFromNamespace();
3349 test_complex_struct_type();
3350 test_WsMoveWriter();
3351 test_WsGetWriterPosition();
3352 test_WsSetWriterPosition();
3353 test_WsWriteXmlBuffer();
3354 test_WsWriteNode();
3355 test_WsCopyNode();
3356 test_text_types();
3357 test_double();
3358 test_field_options();
3359 test_WsWriteText();
3360 test_WsWriteArray();
3361 test_escapes();
3362 test_write_option();
3363 test_datetime();
3364 test_repeating_element();
3365 test_WsWriteQualifiedName();
3366 test_WsWriteBytes();
3367 test_WsWriteChars();
3368 test_WsWriteCharsUtf8();