From 3485f162e918e35c9cdceda89d90e841135677a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Tue, 12 Apr 2022 17:47:31 +0300 Subject: [PATCH] mshtml/tests: Add initial tests for NULL Dispatch objects in scripts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/mshtml/tests/documentmode.js | 58 +++++++++++++++++++ dlls/mshtml/tests/es5.js | 96 +++++++++++++++++++++++++++++++ dlls/mshtml/tests/script.c | 68 ++++++++++++++++++++++ 3 files changed, 222 insertions(+) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 55de9b7158f..5f475cc4a17 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1322,6 +1322,64 @@ sync_test("builtins_diffs", function() { } }); +sync_test("nullDisp", function() { + var v = document.documentMode, nullDisp = external.nullDisp, r; + + todo_wine. + ok(external.getVT(nullDisp) === "VT_NULL", "getVT(nullDisp) is not VT_NULL"); + ok(typeof(nullDisp) === "object", "typeof(nullDisp) = " + typeof(nullDisp)); + ok(nullDisp === nullDisp, "nullDisp !== nullDisp"); + ok(nullDisp === null, "nullDisp === null"); + ok(nullDisp == null, "nullDisp == null"); + ok(!nullDisp === true, "!nullDisp = " + !nullDisp); + ok(String(nullDisp) === "null", "String(nullDisp) = " + String(nullDisp)); + ok(+nullDisp === 0, "+nullDisp !== 0"); + ok(''+nullDisp === "null", "''+nullDisp !== null"); + ok(nullDisp != new Object(), "nullDisp == new Object()"); + ok(new Object() != nullDisp, "new Object() == nullDisp"); + ok((typeof Object(nullDisp)) === "object", "typeof Object(nullDisp) !== 'object'"); + r = Object(nullDisp).toString(); + ok(r === "[object Object]", "Object(nullDisp).toString() = " + r); + ok(Object(nullDisp) != nullDisp, "Object(nullDisp) == nullDisp"); + ok(new Object(nullDisp) != nullDisp, "new Object(nullDisp) == nullDisp"); + + if(v >= 8) { + r = JSON.stringify.call(null, nullDisp); + todo_wine. + ok(r === "null", "JSON.stringify(nullDisp) returned " + r); + } + + try { + (new Object()) instanceof nullDisp; + ok(false, "expected exception on (new Object()) instanceof nullDisp"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "(new Object()) instanceof nullDisp threw " + e.number); + } + + try { + Function.prototype.apply.call(nullDisp, Object, []); + ok(false, "expected exception calling Function.apply on nullDisp"); + }catch(e) { + todo_wine. + ok(e.number === 0xa138a - 0x80000000, "Function.apply on nullDisp threw " + e.number); + } + try { + Function.prototype.call.call(nullDisp, Object); + ok(false, "expected exception calling Function.call on nullDisp"); + }catch(e) { + todo_wine. + ok(e.number === 0xa138a - 0x80000000, "Function.call on nullDisp threw " + e.number); + } + + try { + new nullDisp; + ok(false, "expected exception for new nullDisp"); + }catch(e) { + todo_wine. + ok(e.number === 0xa138f - 0x80000000, "new nullDisp threw " + e.number); + } +}); + sync_test("__proto__", function() { var v = document.documentMode; var r, x = 42; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 6baebbd372c..14ec4f92d29 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -298,9 +298,25 @@ sync_test("getOwnPropertyDescriptor", function() { test_own_data_prop_desc(function(){}, "prototype", true, false, false); test_own_data_prop_desc(Function, "prototype", false, false, false); test_own_data_prop_desc(String.prototype, "constructor", true, false, true); + + try { + Object.getOwnPropertyDescriptor(null, "prototype"); + ok(false, "expected exception with null"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "with null context threw " + n); + } + try { + Object.getOwnPropertyDescriptor(external.nullDisp, "prototype"); + ok(false, "expected exception calling getOwnPropertyDescriptor(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "getOwnPropertyDescriptor(nullDisp) threw " + n); + } }); sync_test("defineProperty", function() { + var nullDisp = external.nullDisp; function test_accessor_prop_desc(obj, prop, orig_desc) { var expected_enumerable = "enumerable" in orig_desc && !!orig_desc.enumerable; var expected_configurable = "configurable" in orig_desc && !!orig_desc.configurable; @@ -548,6 +564,16 @@ sync_test("defineProperty", function() { Object.defineProperty(obj, "funcprop", desc); test_accessor_prop_desc(obj, "funcprop", desc); ok(obj.funcprop(100) === 10, "obj.funcprop() = " + obj.funcprop(100)); + + expect_exception(function() { + Object.defineProperty(null, "funcprop", desc); + }, JS_E_OBJECT_EXPECTED); + expect_exception(function() { + Object.defineProperty(nullDisp, "funcprop", desc); + }, JS_E_OBJECT_EXPECTED); + expect_exception(function() { + Object.defineProperty(obj, "funcprop", nullDisp); + }, JS_E_OBJECT_EXPECTED); }); sync_test("defineProperties", function() { @@ -831,6 +857,13 @@ sync_test("getPrototypeOf", function() { ok(Object.getPrototypeOf(obj) === null, "Object.getPrototypeOf(obj) = " + Object.getPrototypeOf(obj)); ok(Object.getPrototypeOf(external) === null, "Object.getPrototypeOf(non-JS obj) = " + Object.getPrototypeOf(external)); + try { + Object.getOwnPropertyDescriptor(external.nullDisp); + ok(false, "expected exception calling getOwnPropertyDescriptor(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "getOwnPropertyDescriptor(nullDisp) threw " + n); + } }); sync_test("toString", function() { @@ -956,6 +989,14 @@ sync_test("keys", function() { ok(keys === "", "keys([]) = " + keys); ok(Object.keys.length === 1, "Object.keys.length = " + Object.keys.length); + + try { + Object.keys(external.nullDisp); + ok(false, "expected exception calling keys(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "keys(nullDisp) threw " + n); + } }); sync_test("getOwnPropertyNames", function() { @@ -980,6 +1021,14 @@ sync_test("getOwnPropertyNames", function() { ok(names === "length", "names = " + names); ok(Object.getOwnPropertyNames.length === 1, "Object.getOwnPropertyNames.length = " + Object.getOwnPropertyNames.length); + + try { + Object.getOwnPropertyNames(external.nullDisp); + ok(false, "expected exception calling getOwnPropertyNames(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "getOwnPropertyNames(nullDisp) threw " + n); + } }); sync_test("reduce", function() { @@ -1091,6 +1140,14 @@ sync_test("preventExtensions", function() { ok(Object.preventExtensions.length === 1, "Object.preventExtensions.length = " + Object.preventExtensions.length); ok(Object.isExtensible.length === 1, "Object.isExtensible.length = " + Object.isExtensible.length); + + try { + Object.preventExtensions(external.nullDisp); + ok(false, "expected exception calling preventExtensions(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "preventExtensions(nullDisp) threw " + n); + } }); sync_test("freeze", function() { @@ -1143,6 +1200,14 @@ sync_test("freeze", function() { } ok(o[0] === 1, "o[0] = " + o[0]); ok(o.length === 1, "o.length = " + o.length); + + try { + Object.freeze(external.nullDisp); + ok(false, "expected exception freeze(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "freeze(nullDisp) threw " + n); + } }); sync_test("seal", function() { @@ -1195,9 +1260,18 @@ sync_test("seal", function() { } ok(o[0] === 1, "o[0] = " + o[0]); ok(o.length === 1, "o.length = " + o.length); + + try { + Object.seal(external.nullDisp); + ok(false, "expected exception calling seal(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "seal(nullDisp) threw " + n); + } }); sync_test("isFrozen", function() { + var nullDisp = external.nullDisp; ok(Object.isFrozen.length === 1, "Object.isFrozen.length = " + Object.isFrozen.length); ok(Object.isSealed.length === 1, "Object.isSealed.length = " + Object.isSealed.length); @@ -1263,6 +1337,28 @@ sync_test("isFrozen", function() { ok(Object.isFrozen(o) === true, "o is not frozen"); ok(Object.isSealed(o) === true, "o is not sealed"); ok(Object.isExtensible(o) === false, "o is extensible"); + + try { + Object.isFrozen(nullDisp); + ok(false, "expected exception calling isFrozen(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "isFrozen(nullDisp) threw " + n); + } + try { + Object.isSealed(nullDisp); + ok(false, "expected exception calling isSealed(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "isSealed(nullDisp) threw " + n); + } + try { + Object.isExtensible(nullDisp); + ok(false, "expected exception calling isExtensible(nullDisp)"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_OBJECT_EXPECTED, "isExtensible(nullDisp) threw " + n); + } }); sync_test("builtin_context", function() { diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index de42e899635..ceb4fc7c833 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -151,6 +151,8 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_EXTERNAL_BROKEN 0x300004 #define DISPID_EXTERNAL_WIN_SKIP 0x300005 #define DISPID_EXTERNAL_WRITESTREAM 0x300006 +#define DISPID_EXTERNAL_GETVT 0x300007 +#define DISPID_EXTERNAL_NULL_DISP 0x300008 static const GUID CLSID_TestScript = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; @@ -589,6 +591,14 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, *pid = DISPID_EXTERNAL_WRITESTREAM; return S_OK; } + if(!lstrcmpW(bstrName, L"getVT")) { + *pid = DISPID_EXTERNAL_GETVT; + return S_OK; + } + if(!lstrcmpW(bstrName, L"nullDisp")) { + *pid = DISPID_EXTERNAL_NULL_DISP; + return S_OK; + } ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -716,6 +726,64 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID stream_write(V_BSTR(pdp->rgvarg+1), V_BSTR(pdp->rgvarg)); return S_OK; + case DISPID_EXTERNAL_GETVT: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_BSTR; + switch(V_VT(pdp->rgvarg)) { + case VT_EMPTY: + V_BSTR(pvarRes) = SysAllocString(L"VT_EMPTY"); + break; + case VT_NULL: + V_BSTR(pvarRes) = SysAllocString(L"VT_NULL"); + break; + case VT_I4: + V_BSTR(pvarRes) = SysAllocString(L"VT_I4"); + break; + case VT_R8: + V_BSTR(pvarRes) = SysAllocString(L"VT_R8"); + break; + case VT_BSTR: + V_BSTR(pvarRes) = SysAllocString(L"VT_BSTR"); + break; + case VT_DISPATCH: + V_BSTR(pvarRes) = SysAllocString(L"VT_DISPATCH"); + break; + case VT_BOOL: + V_BSTR(pvarRes) = SysAllocString(L"VT_BOOL"); + break; + case VT_DATE: + V_BSTR(pvarRes) = SysAllocString(L"VT_DATE"); + break; + default: + ok(0, "unknown vt %d\n", V_VT(pdp->rgvarg)); + return E_FAIL; + } + + return S_OK; + + case DISPID_EXTERNAL_NULL_DISP: + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = NULL; + return S_OK; + default: ok(0, "unexpected call\n"); return E_NOTIMPL;