package goja import ( "strconv" "testing" ) func TestProxy_Object_target_getPrototypeOf(t *testing.T) { const SCRIPT = ` var proto = {}; var obj = Object.create(proto); var proxy = new Proxy(obj, {}); var p = Object.getPrototypeOf(proxy); assert.sameValue(proto, p); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_Object_proxy_getPrototypeOf(t *testing.T) { const SCRIPT = ` var proto = {}; var proto2 = {}; var obj = Object.create(proto); var proxy = new Proxy(obj, { getPrototypeOf: function(target) { return proto2; } }); var p = Object.getPrototypeOf(proxy); assert.sameValue(proto2, p); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_Object_native_proxy_getPrototypeOf(t *testing.T) { const SCRIPT = ` var p = Object.getPrototypeOf(proxy); assert.sameValue(proto, p); ` runtime := New() prototype := runtime.NewObject() runtime.Set("proto", prototype) target := runtime.NewObject() proxy := runtime.NewProxy(target, &ProxyTrapConfig{ GetPrototypeOf: func(target *Object) *Object { return prototype }, }) runtime.Set("proxy", proxy) runtime.testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_Object_target_setPrototypeOf(t *testing.T) { const SCRIPT = ` var proto = {}; var obj = {}; Object.setPrototypeOf(obj, proto); var proxy = new Proxy(obj, {}); var p = Object.getPrototypeOf(proxy); assert.sameValue(proto, p); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_Object_proxy_setPrototypeOf(t *testing.T) { const SCRIPT = ` var proto = {}; var proto2 = {}; var obj = {}; Object.setPrototypeOf(obj, proto); var proxy = new Proxy(obj, { setPrototypeOf: function(target, prototype) { return Object.setPrototypeOf(target, proto2); } }); Object.setPrototypeOf(proxy, null); var p = Object.getPrototypeOf(proxy); assert.sameValue(proto2, p); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_Object_target_isExtensible(t *testing.T) { const SCRIPT = ` var obj = {}; Object.seal(obj); var proxy = new Proxy(obj, {}); Object.isExtensible(proxy); ` testScript(SCRIPT, valueFalse, t) } func TestProxy_proxy_isExtensible(t *testing.T) { const SCRIPT = ` var obj = {}; Object.seal(obj); var proxy = new Proxy(obj, { isExtensible: function(target) { return false; } }); Object.isExtensible(proxy); ` testScript(SCRIPT, valueFalse, t) } func TestProxy_native_proxy_isExtensible(t *testing.T) { const SCRIPT = ` (function() { Object.preventExtensions(target); return Object.isExtensible(proxy); })(); ` runtime := New() target := runtime.NewObject() runtime.Set("target", target) proxy := runtime.NewProxy(target, &ProxyTrapConfig{ IsExtensible: func(target *Object) (success bool) { return false }, }) runtime.Set("proxy", proxy) val, err := runtime.RunString(SCRIPT) if err != nil { t.Fatal(err) } if val.ToBoolean() { t.Fatal() } } func TestProxy_Object_target_preventExtensions(t *testing.T) { const SCRIPT = ` var obj = { canEvolve: true }; var proxy = new Proxy(obj, {}); Object.preventExtensions(proxy); proxy.canEvolve ` testScript(SCRIPT, valueTrue, t) } func TestProxy_proxy_preventExtensions(t *testing.T) { const SCRIPT = ` var obj = { canEvolve: true }; var proxy = new Proxy(obj, { preventExtensions: function(target) { target.canEvolve = false; Object.preventExtensions(obj); return true; } }); Object.preventExtensions(proxy); proxy.canEvolve; ` testScript(SCRIPT, valueFalse, t) } func TestProxy_native_proxy_preventExtensions(t *testing.T) { const SCRIPT = ` (function() { Object.preventExtensions(proxy); return proxy.canEvolve; })(); ` runtime := New() target := runtime.NewObject() target.Set("canEvolve", true) runtime.Set("target", target) proxy := runtime.NewProxy(target, &ProxyTrapConfig{ PreventExtensions: func(target *Object) (success bool) { target.Set("canEvolve", false) _, err := runtime.RunString("Object.preventExtensions(target)") if err != nil { panic(err) } return true }, }) runtime.Set("proxy", proxy) val, err := runtime.RunString(SCRIPT) if err != nil { t.Fatal(err) } if val.ToBoolean() { t.Fatal() } } func TestProxy_Object_target_getOwnPropertyDescriptor(t *testing.T) { const SCRIPT = ` var desc = { configurable: false, enumerable: false, value: 42, writable: false }; var obj = {}; Object.defineProperty(obj, "foo", desc); var proxy = new Proxy(obj, {}); var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo"); desc2.value ` testScript(SCRIPT, valueInt(42), t) } func TestProxy_proxy_getOwnPropertyDescriptor(t *testing.T) { const SCRIPT = ` var desc = { configurable: false, enumerable: false, value: 42, writable: false }; var proxy_desc = { configurable: false, enumerable: false, value: 24, writable: false }; var obj = {}; Object.defineProperty(obj, "foo", desc); var proxy = new Proxy(obj, { getOwnPropertyDescriptor: function(target, property) { return proxy_desc; } }); assert.throws(TypeError, function() { Object.getOwnPropertyDescriptor(proxy, "foo"); }); undefined; ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_native_proxy_getOwnPropertyDescriptor(t *testing.T) { const SCRIPT = ` (function() { var desc = { configurable: true, enumerable: false, value: 42, writable: false }; var proxy_desc = { configurable: true, enumerable: false, value: 24, writable: false }; var obj = {}; Object.defineProperty(obj, "foo", desc); return function(constructor) { var proxy = constructor(obj, proxy_desc); var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo"); return desc2.value } })(); ` runtime := New() constructor := func(call FunctionCall) Value { target := call.Argument(0).(*Object) proxyDesc := call.Argument(1).(*Object) return runtime.NewProxy(target, &ProxyTrapConfig{ GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { return runtime.toPropertyDescriptor(proxyDesc) }, }).proxy.val } val, err := runtime.RunString(SCRIPT) if err != nil { t.Fatal(err) } if c, ok := val.(*Object).self.assertCallable(); ok { val := c(FunctionCall{ This: val, Arguments: []Value{runtime.ToValue(constructor)}, }) if i := val.ToInteger(); i != 24 { t.Fatalf("val: %d", i) } } else { t.Fatal("not a function") } } func TestProxy_native_proxy_getOwnPropertyDescriptorIdx(t *testing.T) { vm := New() a := vm.NewArray() proxy1 := vm.NewProxy(a, &ProxyTrapConfig{ GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { panic(vm.NewTypeError("GetOwnPropertyDescriptor was called for %q", prop)) }, GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor { if prop >= -1 && prop <= 1 { return PropertyDescriptor{ Value: vm.ToValue(prop), Configurable: FLAG_TRUE, } } return PropertyDescriptor{} }, }) proxy2 := vm.NewProxy(a, &ProxyTrapConfig{ GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { switch prop { case "-1", "0", "1": return PropertyDescriptor{ Value: vm.ToValue(prop), Configurable: FLAG_TRUE, } } return PropertyDescriptor{} }, }) proxy3 := vm.NewProxy(a, &ProxyTrapConfig{ GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { return PropertyDescriptor{ Value: vm.ToValue(prop), Configurable: FLAG_TRUE, } }, GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor { panic(vm.NewTypeError("GetOwnPropertyDescriptorIdx was called for %d", prop)) }, }) vm.Set("proxy1", proxy1) vm.Set("proxy2", proxy2) vm.Set("proxy3", proxy3) vm.testScriptWithTestLibX(` var desc; for (var i = -1; i <= 1; i++) { desc = Object.getOwnPropertyDescriptor(proxy1, i); assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. int "+i); desc = Object.getOwnPropertyDescriptor(proxy1, ""+i); assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. str "+i); desc = Object.getOwnPropertyDescriptor(proxy2, i); assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. int "+i); desc = Object.getOwnPropertyDescriptor(proxy2, ""+i); assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. str "+i); } for (const prop of ["00", " 0", "-0", "01"]) { desc = Object.getOwnPropertyDescriptor(proxy3, prop); assert(deepEqual(desc, {value: prop, writable: false, enumerable: false, configurable: true}), "3. "+prop); } `, _undefined, t) } func TestProxy_native_proxy_getOwnPropertyDescriptorSym(t *testing.T) { vm := New() o := vm.NewObject() sym := NewSymbol("42") vm.Set("sym", sym) proxy := vm.NewProxy(o, &ProxyTrapConfig{ GetOwnPropertyDescriptorSym: func(target *Object, s *Symbol) PropertyDescriptor { if target != o { panic(vm.NewTypeError("Invalid target")) } if s == sym { return PropertyDescriptor{ Value: vm.ToValue("passed"), Writable: FLAG_TRUE, Configurable: FLAG_TRUE, } } return PropertyDescriptor{} }, }) vm.Set("proxy", proxy) vm.testScriptWithTestLibX(` var desc = Object.getOwnPropertyDescriptor(proxy, sym); assert(deepEqual(desc, {value: "passed", writable: true, enumerable: false, configurable: true})); assert.sameValue(Object.getOwnPropertyDescriptor(proxy, Symbol.iterator), undefined); `, _undefined, t) } func TestProxy_native_proxy_getOwnPropertyDescriptor_non_existing(t *testing.T) { vm := New() proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{ GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) { return // empty PropertyDescriptor }, }) vm.Set("proxy", proxy) res, err := vm.RunString(`Object.getOwnPropertyDescriptor(proxy, "foo") === undefined`) if err != nil { t.Fatal(err) } if res != valueTrue { t.Fatal(res) } } func TestProxy_Object_target_defineProperty(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, {}); Object.defineProperty(proxy, "foo", { value: "test123" }); proxy.foo; ` testScript(SCRIPT, asciiString("test123"), t) } func TestProxy_proxy_defineProperty(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, { defineProperty: function(target, prop, descriptor) { target.foo = "321tset"; return true; } }); Object.defineProperty(proxy, "foo", { value: "test123" }); proxy.foo; ` testScript(SCRIPT, asciiString("321tset"), t) } func TestProxy_native_proxy_defineProperty(t *testing.T) { const SCRIPT = ` Object.defineProperty(proxy, "foo", { value: "teststr" }); Object.defineProperty(proxy, "0", { value: "testidx" }); Object.defineProperty(proxy, Symbol.toStringTag, { value: "testsym" }); assert.sameValue(proxy.foo, "teststr-passed-str"); assert.sameValue(proxy[0], "testidx-passed-idx"); assert.sameValue(proxy[Symbol.toStringTag], "testsym-passed-sym"); ` runtime := New() target := runtime.NewObject() proxy := runtime.NewProxy(target, &ProxyTrapConfig{ DefineProperty: func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) { target.Set(key, propertyDescriptor.Value.String()+"-passed-str") return true }, DefinePropertyIdx: func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) { target.Set(strconv.Itoa(key), propertyDescriptor.Value.String()+"-passed-idx") return true }, DefinePropertySym: func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) { target.SetSymbol(key, propertyDescriptor.Value.String()+"-passed-sym") return true }, }) runtime.Set("proxy", proxy) runtime.testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_target_has_in(t *testing.T) { const SCRIPT = ` var obj = { secret: true }; var proxy = new Proxy(obj, {}); "secret" in proxy ` testScript(SCRIPT, valueTrue, t) } func TestProxy_proxy_has_in(t *testing.T) { const SCRIPT = ` var obj = { secret: true }; var proxy = new Proxy(obj, { has: function(target, key) { return key !== "secret"; } }); "secret" in proxy ` testScript(SCRIPT, valueFalse, t) } func TestProxy_target_has_with(t *testing.T) { const SCRIPT = ` var obj = { secret: true }; var proxy = new Proxy(obj, {}); with(proxy) { (secret); } ` testScript(SCRIPT, valueTrue, t) } func TestProxy_proxy_has_with(t *testing.T) { const SCRIPT = ` var obj = { secret: true }; var proxy = new Proxy(obj, { has: function(target, key) { return key !== "secret"; } }); var thrown = false; try { with(proxy) { (secret); } } catch (e) { if (e instanceof ReferenceError) { thrown = true; } else { throw e; } } thrown; ` testScript(SCRIPT, valueTrue, t) } func TestProxy_target_get(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, {}); Object.defineProperty(proxy, "foo", { value: "test123" }); proxy.foo; ` testScript(SCRIPT, asciiString("test123"), t) } func TestProxy_proxy_get(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, { get: function(target, prop, receiver) { return "321tset" } }); Object.defineProperty(proxy, "foo", { value: "test123", configurable: true, }); proxy.foo; ` testScript(SCRIPT, asciiString("321tset"), t) } func TestProxy_proxy_get_json_stringify(t *testing.T) { const SCRIPT = ` var obj = {}; var propValue = "321tset"; var _handler, _target, _prop, _receiver; var proxy = new Proxy(obj, { ownKeys: function() { return ["foo"]; }, getOwnPropertyDescriptor: function(target, prop) { if (prop === "foo") { return { value: propValue, enumerable: true, configurable: true } } }, get: function(target, prop, receiver) { if (prop === "foo") { _prop = prop; _receiver = receiver; return propValue; } return obj[prop]; } }); var res = JSON.stringify(proxy); assert.sameValue(res, '{"foo":"321tset"}'); assert.sameValue(_prop, "foo"); assert.sameValue(_receiver, proxy); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxy_native_proxy_get(t *testing.T) { vm := New() propValueStr := vm.ToValue("321tset") propValueIdx := vm.ToValue("idx") propValueSym := vm.ToValue("sym") sym := NewSymbol("test") obj := vm.NewObject() proxy := vm.NewProxy(obj, &ProxyTrapConfig{ OwnKeys: func(*Object) *Object { return vm.NewArray("0", "foo") }, GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) { if prop == "foo" { return PropertyDescriptor{ Value: propValueStr, Enumerable: FLAG_TRUE, Configurable: FLAG_TRUE, } } if prop == "0" { panic(vm.NewTypeError("GetOwnPropertyDescriptor(0) was called")) } return }, GetOwnPropertyDescriptorIdx: func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) { if prop == 0 { return PropertyDescriptor{ Value: propValueIdx, Enumerable: FLAG_TRUE, Configurable: FLAG_TRUE, } } return }, Get: func(target *Object, property string, receiver Value) (value Value) { if property == "foo" { return propValueStr } if property == "0" { panic(vm.NewTypeError("Get(0) was called")) } return obj.Get(property) }, GetIdx: func(target *Object, property int, receiver Value) (value Value) { if property == 0 { return propValueIdx } return obj.Get(strconv.Itoa(property)) }, GetSym: func(target *Object, property *Symbol, receiver Value) (value Value) { if property == sym { return propValueSym } return obj.GetSymbol(property) }, }) vm.Set("proxy", proxy) res, err := vm.RunString(`JSON.stringify(proxy)`) if err != nil { t.Fatal(err) } if !res.SameAs(asciiString(`{"0":"idx","foo":"321tset"}`)) { t.Fatalf("res: %v", res) } res, err = vm.RunString(`proxy[Symbol.toPrimitive]`) if err != nil { t.Fatal(err) } if !IsUndefined(res) { t.Fatalf("res: %v", res) } res, err = vm.RunString(`proxy.hasOwnProperty(Symbol.toPrimitive)`) if err != nil { t.Fatal(err) } if !res.SameAs(valueFalse) { t.Fatalf("res: %v", res) } if val := vm.ToValue(proxy).(*Object).GetSymbol(sym); val == nil || !val.SameAs(propValueSym) { t.Fatalf("Get(symbol): %v", val) } res, err = vm.RunString(`proxy.toString()`) if err != nil { t.Fatal(err) } if !res.SameAs(asciiString(`[object Object]`)) { t.Fatalf("res: %v", res) } } func TestProxy_native_proxy_set(t *testing.T) { vm := New() propValueStr := vm.ToValue("321tset") propValueIdx := vm.ToValue("idx") propValueSym := vm.ToValue("sym") sym := NewSymbol("test") obj := vm.NewObject() proxy := vm.NewProxy(obj, &ProxyTrapConfig{ Set: func(target *Object, property string, value Value, receiver Value) (success bool) { if property == "str" { obj.Set(property, propValueStr) return true } panic(vm.NewTypeError("Setter for unexpected property: %q", property)) }, SetIdx: func(target *Object, property int, value Value, receiver Value) (success bool) { if property == 0 { obj.Set(strconv.Itoa(property), propValueIdx) return true } panic(vm.NewTypeError("Setter for unexpected idx property: %d", property)) }, SetSym: func(target *Object, property *Symbol, value Value, receiver Value) (success bool) { if property == sym { obj.SetSymbol(property, propValueSym) return true } panic(vm.NewTypeError("Setter for unexpected sym property: %q", property.String())) }, }) proxyObj := vm.ToValue(proxy).ToObject(vm) err := proxyObj.Set("str", "") if err != nil { t.Fatal(err) } err = proxyObj.Set("0", "") if err != nil { t.Fatal(err) } err = proxyObj.SetSymbol(sym, "") if err != nil { t.Fatal(err) } if v := obj.Get("str"); !propValueStr.SameAs(v) { t.Fatal(v) } if v := obj.Get("0"); !propValueIdx.SameAs(v) { t.Fatal(v) } if v := obj.GetSymbol(sym); !propValueSym.SameAs(v) { t.Fatal(v) } } func TestProxy_target_set_prop(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, {}); proxy.foo = "test123"; proxy.foo; ` testScript(SCRIPT, asciiString("test123"), t) } func TestProxy_proxy_set_prop(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, { set: function(target, prop, receiver) { target.foo = "321tset"; return true; } }); proxy.foo = "test123"; proxy.foo; ` testScript(SCRIPT, asciiString("321tset"), t) } func TestProxy_target_set_associative(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, {}); proxy["foo"] = "test123"; proxy.foo; ` testScript(SCRIPT, asciiString("test123"), t) } func TestProxy_proxy_set_associative(t *testing.T) { const SCRIPT = ` var obj = {}; var proxy = new Proxy(obj, { set: function(target, property, value, receiver) { target["foo"] = "321tset"; return true; } }); proxy["foo"] = "test123"; proxy.foo; ` testScript(SCRIPT, asciiString("321tset"), t) } func TestProxy_target_delete(t *testing.T) { const SCRIPT = ` var obj = { foo: "test" }; var proxy = new Proxy(obj, {}); delete proxy.foo; proxy.foo; ` testScript(SCRIPT, _undefined, t) } func TestProxy_proxy_delete(t *testing.T) { const SCRIPT = ` var obj = { foo: "test" }; var proxy = new Proxy(obj, { deleteProperty: function(target, prop) { return true; } }); delete proxy.foo; proxy.foo; ` testScript(SCRIPT, asciiString("test"), t) } func TestProxy_native_delete(t *testing.T) { vm := New() sym := NewSymbol("test") obj := vm.NewObject() var strCalled, idxCalled, symCalled, strNegCalled, idxNegCalled, symNegCalled bool proxy := vm.NewProxy(obj, &ProxyTrapConfig{ DeleteProperty: func(target *Object, property string) (success bool) { if property == "str" { strCalled = true return true } if property == "strNeg" { strNegCalled = true return false } panic(vm.NewTypeError("DeleteProperty for unexpected property: %q", property)) }, DeletePropertyIdx: func(target *Object, property int) (success bool) { if property == 0 { idxCalled = true return true } if property == 1 { idxNegCalled = true return false } panic(vm.NewTypeError("DeletePropertyIdx for unexpected idx property: %d", property)) }, DeletePropertySym: func(target *Object, property *Symbol) (success bool) { if property == sym { symCalled = true return true } if property == SymIterator { symNegCalled = true return false } panic(vm.NewTypeError("DeletePropertySym for unexpected sym property: %q", property.String())) }, }) proxyObj := vm.ToValue(proxy).ToObject(vm) err := proxyObj.Delete("str") if err != nil { t.Fatal(err) } err = proxyObj.Delete("0") if err != nil { t.Fatal(err) } err = proxyObj.DeleteSymbol(sym) if err != nil { t.Fatal(err) } if !strCalled { t.Fatal("str") } if !idxCalled { t.Fatal("idx") } if !symCalled { t.Fatal("sym") } vm.Set("proxy", proxy) _, err = vm.RunString(` if (delete proxy.strNeg) { throw new Error("strNeg"); } if (delete proxy[1]) { throw new Error("idxNeg"); } if (delete proxy[Symbol.iterator]) { throw new Error("symNeg"); } `) if err != nil { t.Fatal(err) } if !strNegCalled { t.Fatal("strNeg") } if !idxNegCalled { t.Fatal("idxNeg") } if !symNegCalled { t.Fatal("symNeg") } } func TestProxy_target_keys(t *testing.T) { const SCRIPT = ` var obj = { foo: "test" }; var proxy = new Proxy(obj, {}); var keys = Object.keys(proxy); if (keys.length != 1) { throw new Error("assertion error"); } ` testScript(SCRIPT, _undefined, t) } func TestProxy_proxy_keys(t *testing.T) { const SCRIPT = ` var obj = { foo: "test" }; var proxy = new Proxy(obj, { ownKeys: function(target) { return ["foo", "bar"]; } }); var keys = Object.keys(proxy); if (keys.length !== 1) { throw new Error("length is "+keys.length); } if (keys[0] !== "foo") { throw new Error("keys[0] is "+keys[0]); } ` testScript(SCRIPT, _undefined, t) } func TestProxy_target_call(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, {}); proxy(); ` testScript(SCRIPT, asciiString("test"), t) } func TestProxy_proxy_call(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, { apply: function(target, thisArg, args) { return "tset" } }); proxy(); ` testScript(SCRIPT, asciiString("tset"), t) } func TestProxy_target_func_apply(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, {}); proxy.apply(); ` testScript(SCRIPT, asciiString("test"), t) } func TestProxy_proxy_func_apply(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, { apply: function(target, thisArg, args) { return "tset" } }); proxy.apply(); ` testScript(SCRIPT, asciiString("tset"), t) } func TestProxy_target_func_call(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, {}); proxy.call(); ` testScript(SCRIPT, asciiString("test"), t) } func TestProxy_proxy_func_call(t *testing.T) { const SCRIPT = ` var obj = function() { return "test" } var proxy = new Proxy(obj, { apply: function(target, thisArg, args) { return "tset" } }); proxy.call(); ` testScript(SCRIPT, asciiString("tset"), t) } func TestProxy_target_new(t *testing.T) { const SCRIPT = ` var obj = function(word) { this.foo = function() { return word; } } var proxy = new Proxy(obj, {}); var instance = new proxy("test"); instance.foo(); ` testScript(SCRIPT, asciiString("test"), t) } func TestProxy_proxy_new(t *testing.T) { const SCRIPT = ` var obj = function(word) { this.foo = function() { return word; } } var proxy = new Proxy(obj, { construct: function(target, args, newTarget) { var word = args[0]; return { foo: function() { return "caught-" + word } } } }); var instance = new proxy("test"); instance.foo(); ` testScript(SCRIPT, asciiString("caught-test"), t) } func TestProxy_Object_native_proxy_ownKeys(t *testing.T) { headers := map[string][]string{ "k0": {}, } vm := New() proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{ OwnKeys: func(target *Object) (object *Object) { keys := make([]interface{}, 0, len(headers)) for k := range headers { keys = append(keys, k) } return vm.ToValue(keys).ToObject(vm) }, GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { v, exists := headers[prop] if exists { return PropertyDescriptor{ Value: vm.ToValue(v), Enumerable: FLAG_TRUE, Configurable: FLAG_TRUE, } } return PropertyDescriptor{} }, }) vm.Set("headers", proxy) v, err := vm.RunString(` var keys = Object.keys(headers); keys.length === 1 && keys[0] === "k0"; `) if err != nil { t.Fatal(err) } if v != valueTrue { t.Fatal("not true", v) } } func TestProxy_proxy_forIn(t *testing.T) { const SCRIPT = ` var proto = { a: 2, protoProp: 1 } Object.defineProperty(proto, "protoNonEnum", { value: 2, writable: true, configurable: true }); var target = Object.create(proto); var proxy = new Proxy(target, { ownKeys: function() { return ["a", "b"]; }, getOwnPropertyDescriptor: function(target, p) { switch (p) { case "a": case "b": return { value: 42, enumerable: true, configurable: true } } }, }); var forInResult = []; for (var key in proxy) { if (forInResult.indexOf(key) !== -1) { throw new Error("Duplicate property "+key); } forInResult.push(key); } forInResult.length === 3 && forInResult[0] === "a" && forInResult[1] === "b" && forInResult[2] === "protoProp"; ` testScript(SCRIPT, valueTrue, t) } func TestProxyExport(t *testing.T) { vm := New() v, err := vm.RunString(` new Proxy({}, {}); `) if err != nil { t.Fatal(err) } v1 := v.Export() if _, ok := v1.(Proxy); !ok { t.Fatalf("Export returned unexpected type: %T", v1) } } func TestProxy_proxy_createTargetNotCallable(t *testing.T) { // from https://github.com/tc39/test262/blob/main/test/built-ins/Proxy/create-target-is-not-callable.js const SCRIPT = ` var p = new Proxy({}, {}); assert.throws(TypeError, function() { p(); }); ` testScriptWithTestLib(SCRIPT, _undefined, t) } func TestProxyEnumerableSymbols(t *testing.T) { const SCRIPT = ` var getOwnKeys = []; var ownKeysResult = [Symbol(), "foo", "0"]; var proxy = new Proxy({}, { getOwnPropertyDescriptor: function(_target, key) { getOwnKeys.push(key); }, ownKeys: function() { return ownKeysResult; }, }); let {...$} = proxy; compareArray(getOwnKeys, ownKeysResult); ` testScriptWithTestLib(SCRIPT, valueTrue, t) }