From ab136a4fc29247432db0e3602130e2f180a552da Mon Sep 17 00:00:00 2001 From: Adam Martinson Date: Wed, 20 Oct 2010 16:35:09 -0500 Subject: [PATCH] msxml3/tests: Internal schema doc storage tests. --- dlls/msxml3/tests/schema.c | 429 ++++++++++++++++++++++++++++--------- 1 file changed, 327 insertions(+), 102 deletions(-) diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index d4fb6f7aa7c..0731d59c8cd 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -2,6 +2,7 @@ * Schema test * * Copyright 2007 Huw Davies + * Copyright 2010 Adam Martinson for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +20,7 @@ */ #include +#include #define COBJMACROS #include "initguid.h" @@ -30,173 +32,395 @@ #include "wine/test.h" -static const WCHAR schema_uri[] = {'x','-','s','c','h','e','m','a',':','t','e','s','t','.','x','m','l',0}; +static const WCHAR xdr_schema_uri[] = {'x','-','s','c','h','e','m','a',':','t','e','s','t','.','x','m','l',0}; -static const WCHAR schema_xml[] = { +static const WCHAR xdr_schema_xml[] = { '<','S','c','h','e','m','a',' ','x','m','l','n','s','=','\"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','x','m','l','-','d','a','t','a','\"','\n', 'x','m','l','n','s',':','d','t','=','\"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','d','a','t','a','t','y','p','e','s','\"','>','\n', '<','/','S','c','h','e','m','a','>','\n',0 }; +static const CHAR xdr_schema1_uri[] = "x-schema:test1.xdr"; +static const CHAR xdr_schema1_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +""; + +static const CHAR xdr_schema2_uri[] = "x-schema:test2.xdr"; +static const CHAR xdr_schema2_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +" " +""; + +static const CHAR xdr_schema3_uri[] = "x-schema:test3.xdr"; +static const CHAR xdr_schema3_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +" " +""; + +static const CHAR xsd_schema1_uri[] = "x-schema:test1.xsd"; +static const CHAR xsd_schema1_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +""; + +static const CHAR xsd_schema2_uri[] = "x-schema:test2.xsd"; +static const CHAR xsd_schema2_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +""; + +static const CHAR xsd_schema3_uri[] = "x-schema:test3.xsd"; +static const CHAR xsd_schema3_xml[] = +"" +"" +" " +" " +" " +" " +" " +" " +" " +""; + + +#define check_ref_expr(expr, n) { \ + LONG ref = expr; \ + ok(ref == n, "expected %i refs, got %i\n", n, ref); \ +} + +#define check_refs(iface, obj, n) { \ + LONG ref = iface ## _AddRef(obj); \ + ok(ref == n+1, "expected %i refs, got %i\n", n+1, ref); \ + ref = iface ## _Release(obj); \ + ok(ref == n, "expected %i refs, got %i\n", n, ref); \ +} + +#define ole_check(expr) { \ + HRESULT r = expr; \ + ok(r == S_OK, #expr " returned %x\n", r); \ +} + +#define ole_expect(expr, expect) { \ + HRESULT r = expr; \ + ok(r == (expect), #expr " returned %x, expected %x\n", r, expect); \ +} + +static BSTR alloced_bstrs[256]; +static int alloced_bstrs_count; + +static BSTR alloc_str_from_narrow(const char *str) +{ + int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */ + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + return ret; +} + +static BSTR _bstr_(const char *str) +{ + assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0])); + alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str); + return alloced_bstrs[alloced_bstrs_count++]; +} + +static void free_bstrs(void) +{ + int i; + for (i = 0; i < alloced_bstrs_count; i++) + SysFreeString(alloced_bstrs[i]); + alloced_bstrs_count = 0; +} + +static VARIANT _variantdoc_(void* doc) +{ + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)doc; + return v; +} + +static void* _create_object(const GUID *clsid, const char *name, const IID *iid, int line) +{ + void *obj = NULL; + HRESULT hr; + + hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, &obj); + if (hr != S_OK) + win_skip_(__FILE__,line)("failed to create %s instance: 0x%08x\n", name, hr); + + return obj; +} + +#define _create(cls) cls, #cls + +#define create_document(iid) _create_object(&_create(CLSID_DOMDocument), iid, __LINE__) + +#define create_document_version(v, iid) _create_object(&_create(CLSID_DOMDocument ## v), iid, __LINE__) + +#define create_cache(iid) _create_object(&_create(CLSID_XMLSchemaCache), iid, __LINE__) + +#define create_cache_version(v, iid) _create_object(&_create(CLSID_XMLSchemaCache ## v), iid, __LINE__) + static void test_schema_refs(void) { IXMLDOMDocument2 *doc; - IXMLDOMSchemaCollection *schema; - HRESULT r; - LONG ref; + IXMLDOMSchemaCollection *cache; VARIANT v; VARIANT_BOOL b; BSTR str; - r = CoCreateInstance( &CLSID_DOMDocument, NULL, - CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); - if( r != S_OK ) + doc = create_document(&IID_IXMLDOMDocument2); + if (!doc) return; - r = CoCreateInstance( &CLSID_XMLSchemaCache, NULL, - CLSCTX_INPROC_SERVER, &IID_IXMLDOMSchemaCollection, (LPVOID*)&schema ); - if( r != S_OK ) + cache = create_cache(&IID_IXMLDOMSchemaCollection); + if(!cache) { IXMLDOMDocument2_Release(doc); return; } - str = SysAllocString(schema_xml); - r = IXMLDOMDocument2_loadXML(doc, str, &b); - ok(r == S_OK, "ret %08x\n", r); + VariantInit(&v); + str = SysAllocString(xdr_schema_xml); + ole_check(IXMLDOMDocument2_loadXML(doc, str, &b)); ok(b == VARIANT_TRUE, "b %04x\n", b); SysFreeString(str); - ref = IXMLDOMDocument2_AddRef(doc); - ok(ref == 2, "ref %d\n", ref); - VariantInit(&v); - V_VT(&v) = VT_DISPATCH; - V_DISPATCH(&v) = (IDispatch*)doc; - - str = SysAllocString(schema_uri); - r = IXMLDOMSchemaCollection_add(schema, str, v); - ok(r == S_OK, "ret %08x\n", r); + str = SysAllocString(xdr_schema_uri); + ole_check(IXMLDOMSchemaCollection_add(cache, str, _variantdoc_(doc))); /* IXMLDOMSchemaCollection_add doesn't add a ref on doc */ - ref = IXMLDOMDocument2_AddRef(doc); - ok(ref == 3, "ref %d\n", ref); - IXMLDOMDocument2_Release(doc); + check_refs(IXMLDOMDocument2, doc, 1); SysFreeString(str); - VariantClear(&v); V_VT(&v) = VT_INT; - r = IXMLDOMDocument2_get_schemas(doc, &v); - ok(r == S_FALSE, "ret %08x\n", r); + ole_expect(IXMLDOMDocument2_get_schemas(doc, &v), S_FALSE); ok(V_VT(&v) == VT_NULL, "vt %x\n", V_VT(&v)); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 2, "ref %d\n", ref); + check_ref_expr(IXMLDOMSchemaCollection_AddRef(cache), 2); V_VT(&v) = VT_DISPATCH; - V_DISPATCH(&v) = (IDispatch*)schema; + V_DISPATCH(&v) = (IDispatch*)cache; /* check that putref_schemas takes a ref */ - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == S_OK, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 4, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); - VariantClear(&v); + ole_check(IXMLDOMDocument2_putref_schemas(doc, v)); + check_refs(IXMLDOMSchemaCollection, cache, 3); + + VariantClear(&v); /* refs now 2 */ - /* refs now 2 */ V_VT(&v) = VT_INT; /* check that get_schemas adds a ref */ - r = IXMLDOMDocument2_get_schemas(doc, &v); - ok(r == S_OK, "ret %08x\n", r); + ole_check(IXMLDOMDocument2_get_schemas(doc, &v)); ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 4, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); + check_refs(IXMLDOMSchemaCollection, cache, 3); - /* refs now 3 */ /* get_schemas doesn't release a ref if passed VT_DISPATCH - ie it doesn't call VariantClear() */ - r = IXMLDOMDocument2_get_schemas(doc, &v); - ok(r == S_OK, "ret %08x\n", r); + ole_check(IXMLDOMDocument2_get_schemas(doc, &v)); ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 5, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); + check_refs(IXMLDOMSchemaCollection, cache, 4); - /* refs now 4 */ /* release the two refs returned by get_schemas */ - IXMLDOMSchemaCollection_Release(schema); - IXMLDOMSchemaCollection_Release(schema); - - /* refs now 2 */ + check_ref_expr(IXMLDOMSchemaCollection_Release(cache), 3); + check_ref_expr(IXMLDOMSchemaCollection_Release(cache), 2); /* check that taking another ref on the document doesn't change the schema's ref count */ - IXMLDOMDocument2_AddRef(doc); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 3, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); - IXMLDOMDocument2_Release(doc); + check_ref_expr(IXMLDOMDocument2_AddRef(doc), 2); + check_refs(IXMLDOMSchemaCollection, cache, 2); + check_ref_expr(IXMLDOMDocument2_Release(doc), 1); - - /* refs now 2 */ /* call putref_schema with some odd variants */ V_VT(&v) = VT_INT; - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == E_FAIL, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 3, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); + ole_expect(IXMLDOMDocument2_putref_schemas(doc, v), E_FAIL); + check_refs(IXMLDOMSchemaCollection, cache, 2); - /* refs now 2 */ /* calling with VT_EMPTY releases the schema */ V_VT(&v) = VT_EMPTY; - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == S_OK, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 2, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); + ole_check(IXMLDOMDocument2_putref_schemas(doc, v)); + check_refs(IXMLDOMSchemaCollection, cache, 1); - /* refs now 1 */ /* try setting with VT_UNKNOWN */ - IXMLDOMSchemaCollection_AddRef(schema); + check_ref_expr(IXMLDOMSchemaCollection_AddRef(cache), 2); V_VT(&v) = VT_UNKNOWN; - V_UNKNOWN(&v) = (IUnknown*)schema; - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == S_OK, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 4, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); - VariantClear(&v); + V_UNKNOWN(&v) = (IUnknown*)cache; + ole_check(IXMLDOMDocument2_putref_schemas(doc, v)); + check_refs(IXMLDOMSchemaCollection, cache, 3); + + VariantClear(&v); /* refs now 2 */ - /* refs now 2 */ /* calling with VT_NULL releases the schema */ V_VT(&v) = VT_NULL; - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == S_OK, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 2, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); + ole_check(IXMLDOMDocument2_putref_schemas(doc, v)); + check_refs(IXMLDOMSchemaCollection, cache, 1); /* refs now 1 */ /* set again */ - IXMLDOMSchemaCollection_AddRef(schema); + check_ref_expr(IXMLDOMSchemaCollection_AddRef(cache), 2); V_VT(&v) = VT_UNKNOWN; - V_UNKNOWN(&v) = (IUnknown*)schema; - r = IXMLDOMDocument2_putref_schemas(doc, v); - ok(r == S_OK, "ret %08x\n", r); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 4, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); - VariantClear(&v); + V_UNKNOWN(&v) = (IUnknown*)cache; + ole_check(IXMLDOMDocument2_putref_schemas(doc, v)); + check_refs(IXMLDOMSchemaCollection, cache, 3); - /* refs now 2 */ + VariantClear(&v); /* refs now 2 */ /* release the final ref on the doc which should release its ref on the schema */ - IXMLDOMDocument2_Release(doc); + check_ref_expr(IXMLDOMDocument2_Release(doc), 0); - ref = IXMLDOMSchemaCollection_AddRef(schema); - ok(ref == 2, "ref %d\n", ref); - IXMLDOMSchemaCollection_Release(schema); - IXMLDOMSchemaCollection_Release(schema); + check_refs(IXMLDOMSchemaCollection, cache, 1); + check_ref_expr(IXMLDOMSchemaCollection_Release(cache), 0); +} + +static void test_collection_refs(void) +{ + IXMLDOMDocument2 *schema1, *schema2, *schema3; + IXMLDOMSchemaCollection *cache1, *cache2, *cache3; + VARIANT_BOOL b; + + schema1 = create_document(&IID_IXMLDOMDocument2); + schema2 = create_document(&IID_IXMLDOMDocument2); + schema3 = create_document(&IID_IXMLDOMDocument2); + + cache1 = create_cache(&IID_IXMLDOMSchemaCollection); + cache2 = create_cache(&IID_IXMLDOMSchemaCollection); + cache3 = create_cache(&IID_IXMLDOMSchemaCollection); + + if (!schema1 || !schema2 || !schema3 || !cache1 || !cache2 || !cache3) + { + if (schema1) IXMLDOMDocument2_Release(schema1); + if (schema2) IXMLDOMDocument2_Release(schema2); + if (schema3) IXMLDOMDocument2_Release(schema3); + + if (cache1) IXMLDOMSchemaCollection_Release(cache1); + if (cache2) IXMLDOMSchemaCollection_Release(cache2); + if (cache3) IXMLDOMSchemaCollection_Release(cache2); + + return; + } + + ole_check(IXMLDOMDocument2_loadXML(schema1, _bstr_(xdr_schema1_xml), &b)); + ok(b == VARIANT_TRUE, "failed to load XML\n"); + + ole_check(IXMLDOMDocument2_loadXML(schema2, _bstr_(xdr_schema2_xml), &b)); + ok(b == VARIANT_TRUE, "failed to load XML\n"); + + ole_check(IXMLDOMDocument2_loadXML(schema3, _bstr_(xdr_schema3_xml), &b)); + ok(b == VARIANT_TRUE, "failed to load XML\n"); + + ole_check(IXMLDOMSchemaCollection_add(cache1, _bstr_(xdr_schema1_uri), _variantdoc_(schema1))); + ole_check(IXMLDOMSchemaCollection_add(cache2, _bstr_(xdr_schema2_uri), _variantdoc_(schema2))); + ole_check(IXMLDOMSchemaCollection_add(cache3, _bstr_(xdr_schema3_uri), _variantdoc_(schema3))); + + check_ref_expr(IXMLDOMDocument2_Release(schema1), 0); + check_ref_expr(IXMLDOMDocument2_Release(schema2), 0); + check_ref_expr(IXMLDOMDocument2_Release(schema3), 0); + schema1 = NULL; + schema2 = NULL; + schema3 = NULL; + + /* releasing the original doc does not affect the schema cache */ + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache1, _bstr_(xdr_schema1_uri), (IXMLDOMNode**)&schema1)); + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache2, _bstr_(xdr_schema2_uri), (IXMLDOMNode**)&schema2)); + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache3, _bstr_(xdr_schema3_uri), (IXMLDOMNode**)&schema3)); + + /* we get a read-only domdoc interface, created just for us */ + if (schema1) todo_wine check_refs(IXMLDOMDocument2, schema1, 1); + if (schema2) todo_wine check_refs(IXMLDOMDocument2, schema2, 1); + if (schema3) todo_wine check_refs(IXMLDOMDocument2, schema3, 1); + + todo_wine ole_check(IXMLDOMSchemaCollection_addCollection(cache2, cache1)); + todo_wine ole_check(IXMLDOMSchemaCollection_addCollection(cache3, cache2)); + + /* merging collections does not affect the ref count */ + check_refs(IXMLDOMSchemaCollection, cache1, 1); + check_refs(IXMLDOMSchemaCollection, cache2, 1); + check_refs(IXMLDOMSchemaCollection, cache3, 1); + + /* nor does it affect the domdoc instances */ + if (schema1) todo_wine check_refs(IXMLDOMDocument2, schema1, 1); + if (schema2) todo_wine check_refs(IXMLDOMDocument2, schema2, 1); + if (schema3) todo_wine check_refs(IXMLDOMDocument2, schema3, 1); + + if (schema1) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema1), 0); + if (schema2) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema2), 0); + if (schema3) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema3), 0); + schema1 = NULL; + schema2 = NULL; + schema3 = NULL; + + /* releasing the domdoc instances doesn't change the cache */ + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache1, _bstr_(xdr_schema1_uri), (IXMLDOMNode**)&schema1)); + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache2, _bstr_(xdr_schema2_uri), (IXMLDOMNode**)&schema2)); + todo_wine ole_check(IXMLDOMSchemaCollection_get(cache3, _bstr_(xdr_schema3_uri), (IXMLDOMNode**)&schema3)); + + /* we can just get them again */ + if (schema1) todo_wine check_refs(IXMLDOMDocument2, schema1, 1); + if (schema2) todo_wine check_refs(IXMLDOMDocument2, schema2, 1); + if (schema3) todo_wine check_refs(IXMLDOMDocument2, schema3, 1); + + /* releasing the caches does not affect the domdoc instances */ + check_ref_expr(IXMLDOMSchemaCollection_Release(cache1), 0); + check_ref_expr(IXMLDOMSchemaCollection_Release(cache2), 0); + check_ref_expr(IXMLDOMSchemaCollection_Release(cache3), 0); + + /* they're just for us */ + if (schema1) todo_wine check_refs(IXMLDOMDocument2, schema1, 1); + if (schema2) todo_wine check_refs(IXMLDOMDocument2, schema2, 1); + if (schema3) todo_wine check_refs(IXMLDOMDocument2, schema3, 1); + + if (schema1) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema1), 0); + if (schema2) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema2), 0); + if (schema3) todo_wine check_ref_expr(IXMLDOMDocument2_Release(schema3), 0); + + free_bstrs(); } START_TEST(schema) @@ -207,6 +431,7 @@ START_TEST(schema) ok( r == S_OK, "failed to init com\n"); test_schema_refs(); + test_collection_refs(); CoUninitialize(); }