mshtml: Added script engine loading test.
authorJacek Caban <jacek@codeweavers.com>
Tue, 25 Mar 2008 01:11:25 +0000 (02:11 +0100)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 25 Mar 2008 10:44:30 +0000 (11:44 +0100)
dlls/mshtml/tests/Makefile.in
dlls/mshtml/tests/script.c [new file with mode: 0644]

index 0aa464515f14e3adc3e69b7b066f61e2be2a19c8..88cf740506bbf3f000eede5e1682a5dc212c291e 100644 (file)
@@ -10,7 +10,8 @@ CTESTS = \
        dom.c \
        htmldoc.c \
        misc.c \
-       protocol.c
+       protocol.c \
+       script.c
 
 @MAKE_TEST_RULES@
 
diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c
new file mode 100644 (file)
index 0000000..8b15d92
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2008 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include <wine/test.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "ole2.h"
+#include "mshtml.h"
+#include "activscp.h"
+
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_NOT_CALLED(func) \
+    do { \
+        ok(!called_ ## func, "unexpected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+#define CLEAR_CALLED(func) \
+    expect_ ## func = called_ ## func = FALSE
+
+
+DEFINE_EXPECT(CreateInstance);
+
+
+#define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}"
+
+static const GUID CLSID_TestScript =
+    {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
+
+static IHTMLDocument2 *notif_doc;
+static BOOL doc_complete;
+
+static const char *debugstr_guid(REFIID riid)
+{
+    static char buf[50];
+
+    sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+            riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
+            riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
+            riid->Data4[5], riid->Data4[6], riid->Data4[7]);
+
+    return buf;
+}
+
+static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
+        REFIID riid, void**ppv)
+{
+    if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
+{
+    if(dispID == DISPID_READYSTATE){
+        BSTR state;
+        HRESULT hres;
+
+        static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
+
+        hres = IHTMLDocument2_get_readyState(notif_doc, &state);
+        ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
+
+        if(!lstrcmpW(state, completeW))
+            doc_complete = TRUE;
+
+        SysFreeString(state);
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
+    PropertyNotifySink_QueryInterface,
+    PropertyNotifySink_AddRef,
+    PropertyNotifySink_Release,
+    PropertyNotifySink_OnChanged,
+    PropertyNotifySink_OnRequestEdit
+};
+
+static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
+
+static IHTMLDocument2 *create_document(void)
+{
+    IHTMLDocument2 *doc;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IHTMLDocument2, (void**)&doc);
+    ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
+
+    return doc;
+}
+
+static IHTMLDocument2 *create_doc_with_string(const char *str)
+{
+    IPersistStreamInit *init;
+    IStream *stream;
+    IHTMLDocument2 *doc;
+    HGLOBAL mem;
+    SIZE_T len;
+
+    notif_doc = doc = create_document();
+    if(!doc)
+        return NULL;
+
+    doc_complete = FALSE;
+    len = strlen(str);
+    mem = GlobalAlloc(0, len);
+    memcpy(mem, str, len);
+    CreateStreamOnHGlobal(mem, TRUE, &stream);
+
+    IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
+
+    IPersistStreamInit_Load(init, stream);
+    IPersistStreamInit_Release(init);
+    IStream_Release(stream);
+
+    return doc;
+}
+
+static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
+{
+    IConnectionPointContainer *container;
+    IConnectionPoint *cp;
+    DWORD cookie;
+    HRESULT hres;
+
+    hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
+    ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
+
+    hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
+    IConnectionPointContainer_Release(container);
+    ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
+
+    hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
+    IConnectionPoint_Release(cp);
+    ok(hres == S_OK, "Advise failed: %08x\n", hres);
+}
+
+typedef void (*domtest_t)(IHTMLDocument2*);
+
+static IHTMLDocument2 *create_and_load_doc(const char *str)
+{
+    IHTMLDocument2 *doc;
+    IHTMLElement *body = NULL;
+    ULONG ref;
+    MSG msg;
+    HRESULT hres;
+
+    doc = create_doc_with_string(str);
+    do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
+
+    while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+
+    hres = IHTMLDocument2_get_body(doc, &body);
+    ok(hres == S_OK, "get_body failed: %08x\n", hres);
+
+    if(!body) {
+        skip("Could not get document body. Assuming no Gecko installed.\n");
+        ref = IHTMLDocument2_Release(doc);
+        ok(!ref, "ref = %d\n", ref);
+        return NULL;
+    }
+
+    IHTMLElement_Release(body);
+    return doc;
+}
+
+static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IActiveScriptParse, riid)) {
+        /* TODO */
+        return E_NOINTERFACE;
+    }
+
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScript_Release(IActiveScript *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid,
+                                            void **ppvObject)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface,
+                                           LPCOLESTR pstrName, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
+                                         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
+                                                IDispatch **ppdisp)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface,
+                                                       SCRIPTTHREADID *pstridThread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface,
+                                                DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface,
+        SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface,
+        SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IActiveScriptVtbl ActiveScriptVtbl = {
+    ActiveScript_QueryInterface,
+    ActiveScript_AddRef,
+    ActiveScript_Release,
+    ActiveScript_SetScriptSite,
+    ActiveScript_GetScriptSite,
+    ActiveScript_SetScriptState,
+    ActiveScript_GetScriptState,
+    ActiveScript_Close,
+    ActiveScript_AddNamedItem,
+    ActiveScript_AddTypeLib,
+    ActiveScript_GetScriptDispatch,
+    ActiveScript_GetCurrentScriptThreadID,
+    ActiveScript_GetScriptThreadID,
+    ActiveScript_GetScriptThreadState,
+    ActiveScript_InterruptScriptThread,
+    ActiveScript_Clone
+};
+
+static IActiveScript ActiveScript = { &ActiveScriptVtbl };
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IMarshal, riid))
+        return E_NOINTERFACE;
+    if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
+        return E_NOINTERFACE;
+
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
+{
+    CHECK_EXPECT(CreateInstance);
+
+    ok(!outer, "outer = %p\n", outer);
+    ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", debugstr_guid(riid));
+    *ppv = &ActiveScript;
+    return S_OK;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    ok(0, "unexpected call\n");
+    return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactoryVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    ClassFactory_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory script_cf = { &ClassFactoryVtbl };
+
+static const char simple_script_str[] =
+    "<html><head></head><body>"
+    "<script language=\"TestScript\">simple script</script>"
+    "</body></html>";
+
+static void test_simple_script(void)
+{
+    IHTMLDocument2 *doc;
+
+    SET_EXPECT(CreateInstance);
+    doc = create_and_load_doc(simple_script_str);
+    CHECK_CALLED(CreateInstance);
+
+    IHTMLDocument2_Release(doc);
+}
+
+static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
+{
+    HKEY hkey;
+    DWORD res;
+
+    if(!init) {
+        RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
+        return TRUE;
+    }
+
+    res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
+    if(res != ERROR_SUCCESS)
+        return FALSE;
+
+    if(def_value)
+        res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
+
+    RegCloseKey(hkey);
+
+    return res == ERROR_SUCCESS;
+}
+
+static BOOL init_registry(BOOL init)
+{
+    return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init)
+        && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}",
+                    NULL, init)
+        && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}",
+                    NULL, init);
+}
+
+static BOOL register_script_engine(void)
+{
+    DWORD regid;
+    HRESULT hres;
+
+    if(!init_registry(TRUE)) {
+        init_registry(FALSE);
+        return FALSE;
+    }
+
+    hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf,
+                                 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
+    ok(hres == S_OK, "Could not register screipt engine: %08x\n", hres);
+
+    return TRUE;
+}
+
+static void gecko_installer_workaround(BOOL disable)
+{
+    HKEY hkey;
+    DWORD res;
+
+    static BOOL has_url = FALSE;
+    static char url[2048];
+
+    if(!disable && !has_url)
+        return;
+
+    res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
+    if(res != ERROR_SUCCESS)
+        return;
+
+    if(disable) {
+        DWORD type, size = sizeof(url);
+
+        res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
+        if(res == ERROR_SUCCESS && type == REG_SZ)
+            has_url = TRUE;
+
+        RegDeleteValue(hkey, "GeckoUrl");
+    }else {
+        RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
+    }
+
+    RegCloseKey(hkey);
+}
+
+START_TEST(script)
+{
+    gecko_installer_workaround(TRUE);
+    CoInitialize(NULL);
+
+    if(register_script_engine()) {
+        test_simple_script();
+        init_registry(FALSE);
+    }else {
+        skip("Could not register TestScript engine\n");
+    }
+
+    CoUninitialize();
+    gecko_installer_workaround(FALSE);
+}