Reactos
1/*
2 * Schema test
3 *
4 * Copyright 2007 Huw Davies
5 * Copyright 2010 Adam Martinson for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include <stdio.h>
23#include <assert.h>
24#define COBJMACROS
25
26#include "ole2.h"
27#include "msxml2.h"
28
29#include "wine/test.h"
30
31static const WCHAR xsd_schema1_uri[] = L"x-schema:test1.xsd";
32static const WCHAR xsd_schema1_xml[] =
33L"<?xml version='1.0'?>"
34"<schema xmlns='http://www.w3.org/2001/XMLSchema'"
35" targetNamespace='x-schema:test1.xsd'>"
36" <element name='root'>"
37" <complexType>"
38" <sequence maxOccurs='unbounded'>"
39" <any/>"
40" </sequence>"
41" </complexType>"
42" </element>"
43"</schema>";
44
45static const WCHAR xsd_schema2_uri[] = L"x-schema:test2.xsd";
46static const WCHAR xsd_schema2_xml[] =
47L"<?xml version='1.0'?>"
48"<schema xmlns='http://www.w3.org/2001/XMLSchema'"
49" targetNamespace='x-schema:test2.xsd'>"
50" <element name='root'>"
51" <complexType>"
52" <sequence maxOccurs='unbounded'>"
53" <any/>"
54" </sequence>"
55" </complexType>"
56" </element>"
57"</schema>";
58
59static const WCHAR xsd_schema3_uri[] = L"x-schema:test3.xsd";
60static const WCHAR xsd_schema3_xml[] =
61L"<?xml version='1.0'?>"
62"<schema xmlns='http://www.w3.org/2001/XMLSchema'"
63" targetNamespace='x-schema:test3.xsd'>"
64" <element name='root'>"
65" <complexType>"
66" <sequence maxOccurs='unbounded'>"
67" <any/>"
68" </sequence>"
69" </complexType>"
70" </element>"
71"</schema>";
72
73static const WCHAR xdr_schema1_uri[] = L"x-schema:test1.xdr";
74static const WCHAR xdr_schema1_xml[] =
75L"<?xml version='1.0'?>"
76"<Schema xmlns='urn:schemas-microsoft-com:xml-data'"
77" xmlns:dt='urn:schemas-microsoft-com:datatypes'"
78" name='test1.xdr'>"
79" <ElementType name='x' dt:type='boolean'/>"
80" <ElementType name='y'>"
81" <datatype dt:type='int'/>"
82" </ElementType>"
83" <ElementType name='z'/>"
84" <ElementType name='root' content='eltOnly' model='open' order='seq'>"
85" <element type='x'/>"
86" <element type='y'/>"
87" <element type='z'/>"
88" </ElementType>"
89"</Schema>";
90
91static const WCHAR xdr_schema2_uri[] = L"x-schema:test2.xdr";
92static const WCHAR xdr_schema2_xml[] =
93L"<?xml version='1.0'?>"
94"<Schema xmlns='urn:schemas-microsoft-com:xml-data'"
95" xmlns:dt='urn:schemas-microsoft-com:datatypes'"
96" name='test2.xdr'>"
97" <ElementType name='x' dt:type='bin.base64'/>"
98" <ElementType name='y' dt:type='uuid'/>"
99" <ElementType name='z'/>"
100" <ElementType name='root' content='eltOnly' model='closed' order='one'>"
101" <element type='x'/>"
102" <element type='y'/>"
103" <element type='z'/>"
104" </ElementType>"
105"</Schema>";
106
107static BSTR alloced_bstrs[256];
108static int alloced_bstrs_count;
109
110static BSTR _bstr_(const WCHAR *str)
111{
112 assert(alloced_bstrs_count < ARRAY_SIZE(alloced_bstrs));
113 alloced_bstrs[alloced_bstrs_count] = SysAllocString(str);
114 return alloced_bstrs[alloced_bstrs_count++];
115}
116
117static void free_bstrs(void)
118{
119 int i;
120 for (i = 0; i < alloced_bstrs_count; i++)
121 SysFreeString(alloced_bstrs[i]);
122 alloced_bstrs_count = 0;
123}
124
125static VARIANT _variantdoc_(void* doc)
126{
127 VARIANT v;
128 V_VT(&v) = VT_DISPATCH;
129 V_DISPATCH(&v) = (IDispatch*)doc;
130 return v;
131}
132
133static IXMLDOMDocument2 *create_document(void)
134{
135 IXMLDOMDocument2 *obj = NULL;
136 HRESULT hr;
137
138 hr = CoCreateInstance(&CLSID_DOMDocument40, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (void **)&obj);
139 ok(hr == S_OK, "Failed to create a document object, hr %#lx.\n", hr);
140
141 return obj;
142}
143
144static void *create_cache(REFIID riid)
145{
146 void *obj = NULL;
147 HRESULT hr;
148
149 hr = CoCreateInstance(&CLSID_XMLSchemaCache40, NULL, CLSCTX_INPROC_SERVER, riid, &obj);
150 ok(hr == S_OK, "Failed to create a document object, hr %#lx.\n", hr);
151
152 return obj;
153}
154
155static HRESULT validate_regex_document(IXMLDOMDocument2 *doc, IXMLDOMDocument2 *schema, IXMLDOMSchemaCollection* cache,
156 const WCHAR *regex, const WCHAR *input)
157{
158 static const WCHAR regex_doc[] =
159L""
160"<?xml version='1.0'?>"
161"<root xmlns='urn:test'>%s</root>";
162
163 static const WCHAR regex_schema[] =
164L"<?xml version='1.0'?>"
165"<schema xmlns='http://www.w3.org/2001/XMLSchema'"
166" targetNamespace='urn:test'>"
167" <element name='root'>"
168" <simpleType>"
169" <restriction base='string'>"
170" <pattern value='%s'/>"
171" </restriction>"
172" </simpleType>"
173" </element>"
174"</schema>";
175
176 WCHAR buffer[1024];
177 IXMLDOMParseError* err;
178 BSTR namespace, bstr;
179 VARIANT_BOOL b;
180 HRESULT hr;
181 VARIANT v;
182
183 VariantInit(&v);
184
185 swprintf(buffer, ARRAY_SIZE(buffer), regex_doc, input);
186 bstr = SysAllocString(buffer);
187 hr = IXMLDOMDocument2_loadXML(doc, bstr, &b);
188 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
189 ok(b == VARIANT_TRUE, "failed to load XML\n");
190 SysFreeString(bstr);
191
192 swprintf(buffer, ARRAY_SIZE(buffer), regex_schema, regex);
193 bstr = SysAllocString(buffer);
194 hr = IXMLDOMDocument2_loadXML(schema, bstr, &b);
195 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
196 ok(b == VARIANT_TRUE, "failed to load XML\n");
197 SysFreeString(bstr);
198
199 /* add the schema to the cache */
200 V_VT(&v) = VT_DISPATCH;
201 V_DISPATCH(&v) = NULL;
202 hr = IXMLDOMDocument2_QueryInterface(schema, &IID_IDispatch, (void**)&V_DISPATCH(&v));
203 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
204 ok(V_DISPATCH(&v) != NULL, "failed to get IDispatch interface\n");
205 namespace = SysAllocString(L"urn:test");
206 hr = IXMLDOMSchemaCollection_add(cache, namespace, v);
207 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
208 SysFreeString(namespace);
209 VariantClear(&v);
210/*
211 if (FAILED(hr))
212 return hr;
213*/
214 /* associate the cache to the doc */
215 V_VT(&v) = VT_DISPATCH;
216 V_DISPATCH(&v) = NULL;
217 hr = IXMLDOMSchemaCollection_QueryInterface(cache, &IID_IDispatch, (void**)&V_DISPATCH(&v));
218 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
219 ok(V_DISPATCH(&v) != NULL, "failed to get IDispatch interface\n");
220 hr = IXMLDOMDocument2_putref_schemas(doc, v);
221 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
222 VariantClear(&v);
223
224 /* validate the doc
225 * only declared elements in the declared order
226 * this is fine */
227 err = NULL;
228 bstr = NULL;
229 hr = IXMLDOMDocument2_validate(doc, &err);
230 ok(err != NULL, "domdoc_validate() should always set err\n");
231 if (IXMLDOMParseError_get_reason(err, &bstr) != S_FALSE)
232 trace("got error: %s\n", wine_dbgstr_w(bstr));
233 SysFreeString(bstr);
234 IXMLDOMParseError_Release(err);
235
236 return hr;
237}
238
239static void test_regex(void)
240{
241 static const struct regex_test
242 {
243 const WCHAR *regex;
244 const WCHAR *input;
245 }
246 tests[] =
247 {
248 { L"\\!", L"!" },
249 { L"\\\"", L"\"" },
250 { L"\\#", L"#" },
251 { L"\\$", L"$" },
252 { L"\\%", L"%" },
253 { L"\\,", L"," },
254 { L"\\/", L"/" },
255 { L"\\:", L":" },
256 { L"\\;", L";" },
257 { L"\\=", L"=" },
258 { L"\\>", L">" },
259 { L"\\@", L"@" },
260 { L"\\`", L"`" },
261 { L"\\~", L"~" },
262 { L"\\uCAFE", L"\xCAFE" },
263 /* non-BMP character in surrogate pairs: */
264 { L"\\uD83D\\uDE00", L"\xD83D\xDE00" },
265 /* "x{,2}" is non-standard and only works on libxml2 <= v2.9.10 */
266 { L"x{0,2}", L"x" }
267 };
268 unsigned int i;
269
270 for (i = 0; i < ARRAY_SIZE(tests); ++i)
271 {
272 const struct regex_test *test = &tests[i];
273 IXMLDOMDocument2 *doc, *schema;
274 IXMLDOMSchemaCollection *cache;
275 HRESULT hr;
276
277 winetest_push_context("Test %s", wine_dbgstr_w(test->regex));
278
279 doc = create_document();
280 schema = create_document();
281 cache = create_cache(&IID_IXMLDOMSchemaCollection);
282
283 hr = validate_regex_document(doc, schema, cache, tests->regex, tests->input);
284 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
285
286 if (doc)
287 IXMLDOMDocument2_Release(doc);
288 if (schema)
289 IXMLDOMDocument2_Release(schema);
290 if (cache)
291 IXMLDOMSchemaCollection_Release(cache);
292
293 winetest_pop_context();
294 }
295}
296
297static void test_get(void)
298{
299 IXMLDOMSchemaCollection2 *cache;
300 IXMLDOMNode *node;
301 HRESULT hr;
302
303 cache = create_cache(&IID_IXMLDOMSchemaCollection2);
304
305 hr = IXMLDOMSchemaCollection2_get(cache, NULL, NULL);
306 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
307
308 hr = IXMLDOMSchemaCollection2_get(cache, _bstr_(L"uri"), &node);
309 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
310
311 IXMLDOMSchemaCollection2_Release(cache);
312 free_bstrs();
313}
314
315static void test_remove(void)
316{
317 IXMLDOMSchemaCollection2 *cache;
318 IXMLDOMDocument2 *doc;
319 VARIANT_BOOL b;
320 HRESULT hr;
321 VARIANT v;
322 LONG len;
323
324 /* ::remove() works for version 4 */
325 cache = create_cache(&IID_IXMLDOMSchemaCollection2);
326
327 doc = create_document();
328 ok(doc != NULL, "got %p\n", doc);
329
330 hr = IXMLDOMDocument2_loadXML(doc, _bstr_(xsd_schema1_xml), &b);
331 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
332
333 V_VT(&v) = VT_DISPATCH;
334 V_DISPATCH(&v) = (IDispatch*)doc;
335 hr = IXMLDOMSchemaCollection2_add(cache, _bstr_(xsd_schema1_uri), v);
336 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
337
338 len = -1;
339 hr = IXMLDOMSchemaCollection2_get_length(cache, &len);
340 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
341 ok(len == 1, "Unexpected length %ld.\n", len);
342
343 hr = IXMLDOMSchemaCollection2_remove(cache, NULL);
344 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
345
346 hr = IXMLDOMSchemaCollection2_remove(cache, _bstr_(L"invaliduri"));
347 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
348
349 len = -1;
350 hr = IXMLDOMSchemaCollection2_get_length(cache, &len);
351 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
352 ok(len == 1, "Unexpected length %ld.\n", len);
353
354 hr = IXMLDOMSchemaCollection2_remove(cache, _bstr_(xsd_schema1_uri));
355 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
356
357 len = -1;
358 hr = IXMLDOMSchemaCollection2_get_length(cache, &len);
359 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
360 ok(len == 0, "Unexpected length %ld.\n", len);
361
362 IXMLDOMDocument2_Release(doc);
363 IXMLDOMSchemaCollection2_Release(cache);
364
365 free_bstrs();
366}
367
368static void test_validate_on_load(void)
369{
370 IXMLDOMSchemaCollection2 *cache;
371 VARIANT_BOOL b;
372 HRESULT hr;
373
374 cache = create_cache(&IID_IXMLDOMSchemaCollection2);
375
376 hr = IXMLDOMSchemaCollection2_get_validateOnLoad(cache, NULL);
377 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
378
379 b = VARIANT_FALSE;
380 hr = IXMLDOMSchemaCollection2_get_validateOnLoad(cache, &b);
381 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
382 ok(b == VARIANT_TRUE, "got %d\n", b);
383
384 IXMLDOMSchemaCollection2_Release(cache);
385}
386
387static void test_collection_content(void)
388{
389 IXMLDOMDocument2 *schema1, *schema2, *schema3, *schema4, *schema5;
390 IXMLDOMSchemaCollection *cache;
391 BSTR content[5] = { 0 };
392 VARIANT_BOOL b;
393 LONG length;
394 HRESULT hr;
395 BSTR bstr;
396 int i, j;
397
398 schema1 = create_document();
399 schema2 = create_document();
400 schema3 = create_document();
401 schema4 = create_document();
402 schema5 = create_document();
403 cache = create_cache(&IID_IXMLDOMSchemaCollection);
404
405 hr = IXMLDOMDocument2_loadXML(schema1, _bstr_(xdr_schema1_xml), &b);
406 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
407 ok(b == VARIANT_TRUE, "failed to load XML\n");
408 hr = IXMLDOMDocument2_loadXML(schema2, _bstr_(xdr_schema2_xml), &b);
409 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
410 ok(b == VARIANT_TRUE, "failed to load XML\n");
411 hr = IXMLDOMDocument2_loadXML(schema3, _bstr_(xsd_schema1_xml), &b);
412 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
413 ok(b == VARIANT_TRUE, "failed to load XML\n");
414 hr = IXMLDOMDocument2_loadXML(schema4, _bstr_(xsd_schema2_xml), &b);
415 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
416 ok(b == VARIANT_TRUE, "failed to load XML\n");
417 hr = IXMLDOMDocument2_loadXML(schema5, _bstr_(xsd_schema3_xml), &b);
418 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
419 ok(b == VARIANT_TRUE, "failed to load XML\n");
420
421 /* combining XDR and XSD schemas in the same cache is fine */
422 hr = IXMLDOMSchemaCollection_add(cache, _bstr_(xdr_schema1_uri), _variantdoc_(schema1));
423 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
424 hr = IXMLDOMSchemaCollection_add(cache, _bstr_(xdr_schema2_uri), _variantdoc_(schema2));
425 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
426 hr = IXMLDOMSchemaCollection_add(cache, _bstr_(xsd_schema1_uri), _variantdoc_(schema3));
427 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
428 hr = IXMLDOMSchemaCollection_add(cache, _bstr_(xsd_schema2_uri), _variantdoc_(schema4));
429 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
430 hr = IXMLDOMSchemaCollection_add(cache, _bstr_(xsd_schema3_uri), _variantdoc_(schema5));
431 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
432
433 length = -1;
434 hr = IXMLDOMSchemaCollection_get_length(cache, &length);
435 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
436 ok(length == 5, "Unexpected length %ld.\n", length);
437
438 for (i = 0; i < 5; ++i)
439 {
440 bstr = NULL;
441 hr = IXMLDOMSchemaCollection_get_namespaceURI(cache, i, &bstr);
442 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
443 ok(bstr != NULL && *bstr, "expected non-empty string\n");
444
445 for (j = 0; j < i; ++j)
446 ok(wcscmp(content[j], bstr), "got duplicate entry\n");
447 content[i] = bstr;
448 }
449
450 for (i = 0; i < 5; ++i)
451 {
452 SysFreeString(content[i]);
453 content[i] = NULL;
454 }
455
456 IXMLDOMDocument2_Release(schema1);
457 IXMLDOMDocument2_Release(schema2);
458 IXMLDOMDocument2_Release(schema3);
459 IXMLDOMDocument2_Release(schema4);
460 IXMLDOMDocument2_Release(schema5);
461
462 IXMLDOMSchemaCollection_Release(cache);
463 free_bstrs();
464}
465
466START_TEST(schema)
467{
468 IUnknown *obj;
469 HRESULT hr;
470
471 hr = CoInitialize(NULL);
472 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
473
474 hr = CoCreateInstance(&CLSID_DOMDocument40, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (void **)&obj);
475 if (FAILED(hr))
476 {
477 win_skip("DOMDocument40 is not supported.\n");
478 CoUninitialize();
479 return;
480 }
481 IUnknown_Release(obj);
482
483 test_regex();
484 test_get();
485 test_remove();
486 test_validate_on_load();
487 test_collection_content();
488
489 CoUninitialize();
490}