1276 lines
27 KiB
Go
1276 lines
27 KiB
Go
|
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)
|
||
|
}
|