>From 533f9b3ee5e2d83a02039397db74908f82292b06 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Sat, 26 Nov 2011 16:41:39 +0300
Subject: [PATCH 1/4] Some refcount tests to show details of internal DOM representation

---
 dlls/msxml3/tests/domdoc.c |  275 +++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 247 insertions(+), 28 deletions(-)

diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 0e36ae7..7de1837 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -43,6 +43,7 @@
 
 DEFINE_GUID(SID_SContainerDispatch, 0xb722be00, 0x4e68, 0x101b, 0xa2, 0xbc, 0x00, 0xaa, 0x00, 0x40, 0x47, 0x70);
 DEFINE_GUID(SID_UnknownSID, 0x75dd09cb, 0x6c40, 0x11d5, 0x85, 0x43, 0x00, 0xc0, 0x4f, 0xa0, 0xfb, 0xa3);
+DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
 
 #define DEFINE_EXPECT(func) \
     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
@@ -3087,29 +3088,202 @@ static void test_domnode( void )
     free_bstrs();
 }
 
+typedef struct {
+    DOMNodeType type;
+    REFIID iid;
+} refcount_test_t;
+
+static const refcount_test_t refcount_test[] = {
+    { NODE_ELEMENT,                &IID_IXMLDOMElement },
+    { NODE_ATTRIBUTE,              &IID_IXMLDOMAttribute },
+    { NODE_TEXT,                   &IID_IXMLDOMText },
+    { NODE_CDATA_SECTION,          &IID_IXMLDOMCDATASection },
+    { NODE_ENTITY_REFERENCE,       &IID_IXMLDOMEntityReference },
+    { NODE_PROCESSING_INSTRUCTION, &IID_IXMLDOMProcessingInstruction },
+    { NODE_COMMENT,                &IID_IXMLDOMComment },
+    { NODE_DOCUMENT_FRAGMENT,      &IID_IXMLDOMDocumentFragment },
+    { NODE_INVALID,                &IID_NULL }
+};
+
 static void test_refs(void)
 {
-    HRESULT r;
-    VARIANT_BOOL b;
-    IXMLDOMDocument *doc;
-    IXMLDOMElement *element = NULL;
-    IXMLDOMNode *node = NULL, *node2;
+    IXMLDOMImplementation *impl, *impl2;
+    IXMLDOMElement *element, *elem2;
     IXMLDOMNodeList *node_list = NULL;
-    LONG ref;
+    IXMLDOMNode *node, *node2, *node3;
+    const refcount_test_t *ptr;
+    IXMLDOMDocument *doc;
     IUnknown *unk, *unk2;
+    VARIANT_BOOL b;
+    HRESULT hr;
+    LONG ref;
 
     doc = create_document(&IID_IXMLDOMDocument);
     if (!doc) return;
 
+    ptr = refcount_test;
+    while (ptr->type != NODE_INVALID)
+    {
+        IUnknown *node_typed, *node_typed2;
+        IDispatchEx *dispex, *dispex2;
+        IDispatch *disp, *disp2;
+        VARIANT type;
+
+        V_VT(&type) = VT_I1;
+        V_I1(&type) = ptr->type;
+
+        EXPECT_REF(doc, 1);
+        hr = IXMLDOMDocument_createNode(doc, type, _bstr_("name"), NULL, &node);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(doc, 1);
+        EXPECT_REF(node, 1);
+
+        /* try IDispatch and IUnknown from IXMLDOMNode */
+        hr = IXMLDOMNode_QueryInterface(node, &IID_IUnknown, (void**)&unk);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(unk, 2);
+todo_wine {
+        EXPECT_REF(node, 1);
+        ok(unk != (IUnknown*)node, "%d: got %p and %p\n", ptr->type, unk, node);
+}
+        EXPECT_REF(unk, 2);
+        hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
+        EXPECT_HR(hr, S_OK);
+        todo_wine ok(unk != (IUnknown*)disp, "%d: got %p and %p\n", ptr->type, unk, disp);
+        EXPECT_REF(unk, 3);
+        todo_wine EXPECT_REF(disp, 1);
+
+        EXPECT_REF(unk, 3);
+        hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp2);
+        EXPECT_HR(hr, S_OK);
+        todo_wine ok(disp != disp2, "%d: got %p and %p\n", ptr->type, disp, disp2);
+        EXPECT_REF(unk, 4);
+        todo_wine EXPECT_REF(disp2, 1);
+
+        IDispatch_Release(disp);
+        IDispatch_Release(disp2);
+
+        /* get IXMLDOMNode from this IUnknown */
+        EXPECT_REF(unk, 2);
+        hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMNode, (void**)&node2);
+        EXPECT_HR(hr, S_OK);
+        todo_wine ok(unk != (IUnknown*)node2, "%d: got %p and %p\n", ptr->type, unk, node2);
+        EXPECT_REF(unk, 3);
+        todo_wine EXPECT_REF(node2, 1);
+
+        EXPECT_REF(unk, 3);
+        hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMNode, (void**)&node3);
+        EXPECT_HR(hr, S_OK);
+        todo_wine ok(node2 != node3, "%d: got %p and %p\n", ptr->type, node2, node3);
+        EXPECT_REF(unk, 4);
+        todo_wine EXPECT_REF(node3, 1);
+
+        IXMLDOMNode_Release(node2);
+        IXMLDOMNode_Release(node3);
+
+        /* try IDispatchEx from IUnknown */
+        EXPECT_REF(unk, 2);
+        hr = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex);
+        EXPECT_HR(hr, S_OK);
+        ok(unk != (IUnknown*)dispex, "%d: got %p and %p\n", ptr->type, unk, dispex);
+        EXPECT_REF(unk, 3);
+        todo_wine EXPECT_REF(dispex, 1);
+
+        EXPECT_REF(unk, 3);
+        hr = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex2);
+        EXPECT_HR(hr, S_OK);
+        todo_wine ok(dispex != dispex2, "%d: got %p and %p\n", ptr->type, dispex, dispex2);
+        EXPECT_REF(unk, 4);
+        todo_wine EXPECT_REF(dispex2, 1);
+
+        IDispatch_Release(dispex);
+        IDispatch_Release(dispex2);
+
+        /* try corresponding IXMLDOM* */
+        EXPECT_REF(unk, 2);
+        hr = IUnknown_QueryInterface(unk, ptr->iid, (void**)&node_typed);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(unk, 3);
+        hr = IUnknown_QueryInterface(unk, ptr->iid, (void**)&node_typed2);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(unk, 4);
+        todo_wine ok(node_typed != node_typed2, "%d: got %p and %p\n", ptr->type, node_typed, node_typed2);
+        IUnknown_Release(node_typed);
+        IUnknown_Release(node_typed2);
+
+        /* try invalid IXMLDOM* */
+        hr = IUnknown_QueryInterface(unk, (ptr+1)->iid, (void**)&node_typed);
+        EXPECT_HR(hr, E_NOINTERFACE);
+
+        IUnknown_Release(unk);
+
+        EXPECT_REF(node, 1);
+        hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMNode, (void**)&node2);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(node, 2);
+        ok(node == node2, "%d: got %p and %p\n", ptr->type, node, node2);
+
+        EXPECT_REF(node, 2);
+        hr = IXMLDOMNode_QueryInterface(node, ptr->iid, (void**)&node_typed);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(node, 3);
+todo_wine {
+        EXPECT_REF(node_typed, 2);
+        ok((IUnknown*)node != node_typed, "%d: got %p and %p\n", ptr->type, node, node_typed);
+}
+        IUnknown_Release(node_typed);
+
+        IXMLDOMNode_Release(node2);
+        IXMLDOMNode_Release(node);
+
+        ptr++;
+    }
+
     EXPECT_REF(doc, 1);
     ref = IXMLDOMDocument_Release(doc);
     ok( ref == 0, "ref %d\n", ref);
 
+    /* check IUnknown after releasing DOM iface */
+    doc = create_document(&IID_IXMLDOMDocument);
+    EXPECT_REF(doc, 1);
+    hr = IXMLDOMDocument_QueryInterface(doc, &IID_IUnknown, (void**)&unk);
+    EXPECT_HR(hr, S_OK);
+todo_wine {
+    EXPECT_REF(unk, 3);
+    EXPECT_REF(doc, 1);
+}
+    IXMLDOMDocument_Release(doc);
+    EXPECT_REF(unk, 1);
+    IUnknown_Release(unk);
+
     doc = create_document(&IID_IXMLDOMDocument);
     if (!doc) return;
 
-    r = IXMLDOMDocument_loadXML( doc, _bstr_(complete4A), &b );
-    ok( r == S_OK, "loadXML failed\n");
+    EXPECT_REF(doc, 1);
+    hr = IXMLDOMDocument_QueryInterface(doc, &IID_IUnknown, (void**)&unk);
+    EXPECT_HR(hr, S_OK);
+todo_wine {
+    EXPECT_REF(unk, 3);
+    EXPECT_REF(doc, 1);
+}
+    IUnknown_Release(unk);
+
+    /* IXMLDOMImplementation */
+    EXPECT_REF(doc, 1);
+    hr = IXMLDOMDocument_get_implementation(doc, &impl);
+    EXPECT_HR(hr, S_OK);
+    EXPECT_REF(doc, 1);
+    EXPECT_REF(impl, 1);
+    hr = IXMLDOMDocument_get_implementation(doc, &impl2);
+    EXPECT_HR(hr, S_OK);
+    EXPECT_REF(doc, 1);
+    EXPECT_REF(impl2, 1);
+    ok(impl != impl2, "got %p, %p\n", impl, impl2);
+    IXMLDOMImplementation_Release(impl);
+    IXMLDOMImplementation_Release(impl2);
+
+    hr = IXMLDOMDocument_loadXML( doc, _bstr_(complete4A), &b );
+    EXPECT_HR(hr, S_OK);
     ok( b == VARIANT_TRUE, "failed to load XML string\n");
 
     EXPECT_REF(doc, 1);
@@ -3121,30 +3295,75 @@ static void test_refs(void)
     IXMLDOMDocument_Release( doc );
     IXMLDOMDocument_Release( doc );
 
-    r = IXMLDOMDocument_get_documentElement( doc, &element );
-    ok( r == S_OK, "should be a document element\n");
-    ok( element != NULL, "should be an element\n");
-
     EXPECT_REF(doc, 1);
-    todo_wine EXPECT_REF(element, 2);
+    hr = IXMLDOMDocument_QueryInterface(doc, &IID_IUnknown, (void**)&unk);
+    EXPECT_HR(hr, S_OK);
+todo_wine {
+    EXPECT_REF(unk, 3);
+    EXPECT_REF(doc, 1);
+}
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    EXPECT_HR(hr, S_OK);
+todo_wine {
+    EXPECT_REF(doc, 1);
+    EXPECT_REF(element, 2);
+}
+    hr = IXMLDOMDocument_get_documentElement(doc, &elem2);
+    EXPECT_HR(hr, S_OK);
 
+todo_wine {
+    EXPECT_REF(doc, 1);
+    EXPECT_REF(element, 2);
+    EXPECT_REF(elem2, 2);
+}
     IXMLDOMElement_AddRef(element);
     todo_wine EXPECT_REF(element, 3);
     IXMLDOMElement_Release(element);
 
-    r = IXMLDOMElement_get_childNodes( element, &node_list );
-    ok( r == S_OK, "rets %08x\n", r);
+    /* get IUnknown from a node doesn't touch node instance refcount */
+    hr = IXMLDOMElement_QueryInterface(element, &IID_IUnknown, (void**)&unk);
+    EXPECT_HR(hr, S_OK);
+    EXPECT_REF(element, 2);
+todo_wine {
+    EXPECT_REF(unk, 4);
+    EXPECT_REF(elem2, 2);
+}
+    hr = IXMLDOMElement_QueryInterface(elem2, &IID_IUnknown, (void**)&unk2);
+    EXPECT_HR(hr, S_OK);
+todo_wine {
+    EXPECT_REF(unk, 5);
+    EXPECT_REF(unk2, 5);
+}
+    EXPECT_REF(element, 2);
+    EXPECT_REF(elem2, 2);
+
+    todo_wine ok(unk == unk2, "got %p and %p\n", unk, unk2);
+
+    IUnknown_Release(unk);
+    IUnknown_Release(unk2);
+
+    /* IUnknown refcount is not affected by node refcount */
+    todo_wine EXPECT_REF(unk2, 3);
+    IXMLDOMElement_AddRef(elem2);
+    todo_wine EXPECT_REF(unk2, 3);
+    IXMLDOMElement_Release(elem2);
+
+    IXMLDOMElement_Release(elem2);
+    todo_wine EXPECT_REF(unk2, 2);
+
+    hr = IXMLDOMElement_get_childNodes( element, &node_list );
+    EXPECT_HR(hr, S_OK);
 
     todo_wine EXPECT_REF(element, 2);
     EXPECT_REF(node_list, 1);
 
-    IXMLDOMNodeList_get_item( node_list, 0, &node );
-    ok( r == S_OK, "rets %08x\n", r);
+    hr = IXMLDOMNodeList_get_item( node_list, 0, &node );
+    EXPECT_HR(hr, S_OK);
     EXPECT_REF(node_list, 1);
     EXPECT_REF(node, 1);
 
-    IXMLDOMNodeList_get_item( node_list, 0, &node2 );
-    ok( r == S_OK, "rets %08x\n", r);
+    hr = IXMLDOMNodeList_get_item( node_list, 0, &node2 );
+    EXPECT_HR(hr, S_OK);
     EXPECT_REF(node_list, 1);
     EXPECT_REF(node2, 1);
 
@@ -3159,22 +3378,22 @@ static void test_refs(void)
     ok( node != node2, "node %p node2 %p\n", node, node2 );
 
     ref = IXMLDOMDocument_Release( doc );
-    ok( ref == 0, "ref %d\n", ref );
+    todo_wine ok( ref == 0, "ref %d\n", ref );
 
     todo_wine EXPECT_REF(element, 2);
 
     /* IUnknown must be unique however we obtain it */
-    r = IXMLDOMElement_QueryInterface( element, &IID_IUnknown, (void**)&unk );
-    ok( r == S_OK, "rets %08x\n", r );
+    hr = IXMLDOMElement_QueryInterface(element, &IID_IUnknown, (void**)&unk);
+    EXPECT_HR(hr, S_OK);
     EXPECT_REF(element, 2);
-    r = IXMLDOMElement_QueryInterface( element, &IID_IXMLDOMNode, (void**)&node );
-    ok( r == S_OK, "rets %08x\n", r );
+    hr = IXMLDOMElement_QueryInterface(element, &IID_IXMLDOMNode, (void**)&node);
+    EXPECT_HR(hr, S_OK);
     todo_wine EXPECT_REF(element, 2);
-    r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (void**)&unk2 );
-    ok( r == S_OK, "rets %08x\n", r );
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IUnknown, (void**)&unk2);
+    EXPECT_HR(hr, S_OK);
     todo_wine EXPECT_REF(element, 2);
-    ok( unk == unk2, "unk %p unk2 %p\n", unk, unk2 );
-    todo_wine ok( element != (void*)node, "node %p element %p\n", node, element );
+    ok(unk == unk2, "unk %p unk2 %p\n", unk, unk2);
+    todo_wine ok(element != (void*)node, "node %p element %p\n", node, element);
 
     IUnknown_Release( unk2 );
     IUnknown_Release( unk );
-- 
1.5.6.5


