Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 44 ++++++++++++++ dlls/mshtml/tests/documentmode.js | 95 +++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index d7650ff..bf0be64 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -337,6 +337,49 @@ done: return S_OK; }
+static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t desc; + const WCHAR *name; + jsstr_t *name_str; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + goto done; + + if(argc < 2 || !is_object_instance(argv[1])) + return JS_E_FUNCTION_EXPECTED; + + desc.setter = to_jsdisp(get_object(argv[1])); + if(!desc.setter) { + FIXME("setter is not JS object\n"); + return E_NOTIMPL; + } + /* FIXME: Check IsCallable */ + + hres = to_flat_string(ctx, argv[0], &name_str, &name); + if(FAILED(hres)) + return hres; + + desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = FALSE; + desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + desc.getter = NULL; + hres = jsdisp_define_property(jsthis, name, &desc); + + jsstr_release(name_str); + if(FAILED(hres)) + return hres; +done: + if(r) + *r = jsval_undefined(); + return S_OK; +} + HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -409,6 +452,7 @@ static void Object_destructor(jsdisp_t *dispex)
static const builtin_prop_t Object_props[] = { {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2}, + {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2}, {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1}, {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1}, {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 18dd65e..4a776f8 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1503,6 +1503,101 @@ sync_test("__defineGetter__", function() { ok(x.bar === "wine", "x.bar with getter = " + x.bar); });
+sync_test("__defineSetter__", function() { + var v = document.documentMode; + var r, x = 42; + + if(v < 11) { + ok(x.__defineSetter__ === undefined, "x.__defineSetter__ = " + x.__defineSetter__); + ok(!("__defineSetter__" in Object), "Object.__defineSetter__ = " + Object.__defineSetter__); + return; + } + ok(Object.prototype.hasOwnProperty("__defineSetter__"), "__defineSetter__ is not a property of Object.prototype"); + ok(Object.prototype.__defineSetter__.length === 2, "__defineSetter__.length = " + Object.prototype.__defineSetter__.length); + + function getter() { return "wine"; } + function setter(val) { this.setterVal = val - 1; } + + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ on 42 returned " + r); + ok(x.foo === undefined, "42.foo = " + x.foo); + + x = {}; + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ returned " + r); + ok(x.setterVal === undefined, "x.setterVal = " + x.setterVal); + x.foo = 13; + ok(x.setterVal === 12, "x.setterVal = " + x.setterVal); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo value = " + r.value); + ok(r.get === undefined, "x.foo get = " + r.get); + ok(r.set === setter, "x.foo set = " + r.set); + ok(r.writable === undefined, "x.foo writable = " + r.writable); + ok(r.enumerable === true, "x.foo enumerable = " + r.enumerable); + ok(r.configurable === true, "x.foo configurable = " + r.configurable); + + Object.defineProperty(x, "foo", { get: getter, set: undefined, configurable: false }); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo getter value = " + r.value); + ok(r.get === getter, "x.foo getter get = " + r.get); + ok(r.set === undefined, "x.foo getter set = " + r.set); + ok(r.writable === undefined, "x.foo getter writable = " + r.writable); + ok(r.enumerable === true, "x.foo getter enumerable = " + r.enumerable); + ok(r.configurable === false, "x.foo getter configurable = " + r.configurable); + try { + x.__defineSetter__("foo", setter); + ok(false, "expected exception calling __defineSetter__ on non-configurable property"); + }catch(e) { + ok(e.number === 0xa13d6 - 0x80000000, "__defineSetter__ on non-configurable property threw exception " + e.number); + } + + r = Object.prototype.__defineSetter__.call(undefined, "bar", setter); + ok(r === undefined, "__defineSetter__ on undefined returned " + r); + r = Object.prototype.__defineSetter__.call(null, "bar", setter); + ok(r === undefined, "__defineSetter__ on null returned " + r); + r = x.__defineSetter__(null, setter); + ok(r === undefined, "__defineSetter__ null prop returned " + r); + x["null"] = 100; + ok(x.setterVal === 99, "x.setterVal after setting x.null = " + x.setterVal); + r = x.__defineSetter__(50, setter); + ok(r === undefined, "__defineSetter__ 50 prop returned " + r); + x["50"] = 33; + ok(x.setterVal === 32, "x.setterVal after setting x.50 = " + x.setterVal); + + try { + x.__defineSetter__("bar", true); + ok(false, "expected exception calling __defineSetter__ with bool"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with bool threw exception " + e.number); + } + try { + x.__defineSetter__("bar", undefined); + ok(false, "expected exception calling __defineSetter__ with undefined"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with undefined threw exception " + e.number); + } + try { + x.__defineSetter__("bar", null); + ok(false, "expected exception calling __defineSetter__ with null"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with null threw exception " + e.number); + } + try { + Object.prototype.__defineSetter__.call(x, "bar"); + ok(false, "expected exception calling __defineSetter__ with only one arg"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with only one arg threw exception " + e.number); + } + + x.bar = "test"; + ok(x.bar === "test", "x.bar = " + x.bar); + x.__defineSetter__("bar", setter); + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + x.bar = 10; + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + ok(x.setterVal === 9, "x.setterVal after setting bar = " + x.setterVal); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false;