Index: test/mjsunit/harmony/proxies-function.js |
=================================================================== |
--- test/mjsunit/harmony/proxies-function.js (revision 9808) |
+++ test/mjsunit/harmony/proxies-function.js (working copy) |
@@ -38,6 +38,13 @@ |
} |
+// Ensures that checking the "length" property of a function proxy doesn't |
+// crash due to lack of a [[Get]] method. |
+var handler = { |
+ get : function(r, n) { return n == "length" ? 2 : undefined } |
+} |
+ |
+ |
// Calling (call, Function.prototype.call, Function.prototype.apply, |
// Function.prototype.bind). |
@@ -46,81 +53,167 @@ |
function TestCall(isStrict, callTrap) { |
assertEquals(42, callTrap(5, 37)) |
- // TODO(rossberg): unrelated bug: this does not succeed for optimized code: |
- // assertEquals(isStrict ? undefined : global_object, receiver) |
+ assertEquals(isStrict ? undefined : global_object, receiver) |
- var f = Proxy.createFunction({}, callTrap) |
+ var handler = { |
+ get: function(r, k) { |
+ return k == "length" ? 2 : Function.prototype[k] |
+ } |
+ } |
+ var f = Proxy.createFunction(handler, callTrap) |
+ |
receiver = 333 |
assertEquals(42, f(11, 31)) |
assertEquals(isStrict ? undefined : global_object, receiver) |
- var o = {} |
+ var o = {f: f} |
+ receiver = 333 |
+ assertEquals(42, o.f(10, 32)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, o["f"](9, 33)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, (1, o).f(8, 34)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, (1, o)["f"](7, 35)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, f.call(o, 32, 10)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, f.call(null, 33, 9)) |
+ assertSame(isStrict ? null : global_object, receiver) |
+ receiver = 333 |
+ assertEquals(44, f.call(2, 21, 23)) |
+ assertSame(2, receiver.valueOf()) |
+ receiver = 333 |
assertEquals(42, Function.prototype.call.call(f, o, 20, 22)) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
+ receiver = 333 |
assertEquals(43, Function.prototype.call.call(f, null, 20, 23)) |
- assertEquals(isStrict ? null : global_object, receiver) |
+ assertSame(isStrict ? null : global_object, receiver) |
assertEquals(44, Function.prototype.call.call(f, 2, 21, 23)) |
assertEquals(2, receiver.valueOf()) |
receiver = 333 |
+ assertEquals(32, f.apply(o, [16, 16])) |
+ assertSame(o, receiver) |
+ receiver = 333 |
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15])) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
+ |
var ff = Function.prototype.bind.call(f, o, 12) |
+ assertTrue(ff.length <= 1) // TODO(rossberg): Not spec'ed yet, be lax. |
receiver = 333 |
assertEquals(42, ff(30)) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
receiver = 333 |
assertEquals(32, Function.prototype.apply.call(ff, {}, [20])) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
+ var fff = Function.prototype.bind.call(ff, o, 30) |
+ assertEquals(0, fff.length) |
+ receiver = 333 |
+ assertEquals(42, fff()) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, Function.prototype.call.call(fff, {})) |
+ assertSame(o, receiver) |
+ |
var f = CreateFrozen({}, callTrap) |
receiver = 333 |
assertEquals(42, f(11, 31)) |
- // TODO(rossberg): unrelated bug: this does not succeed for optimized code. |
- // assertEquals(isStrict ? undefined : global, receiver) |
+ assertSame(isStrict ? undefined : global_object, receiver) |
+ var o = {f: f} |
receiver = 333 |
+ assertEquals(42, o.f(10, 32)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, o["f"](9, 33)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, (1, o).f(8, 34)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
+ assertEquals(42, (1, o)["f"](7, 35)) |
+ assertSame(o, receiver) |
+ receiver = 333 |
assertEquals(42, Function.prototype.call.call(f, o, 20, 22)) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
receiver = 333 |
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15])) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
receiver = 333 |
assertEquals(42, ff(30)) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
receiver = 333 |
assertEquals(32, Function.prototype.apply.call(ff, {}, [20])) |
- assertEquals(o, receiver) |
+ assertSame(o, receiver) |
} |
TestCall(false, function(x, y) { |
- receiver = this; return x + y |
+ receiver = this |
+ return x + y |
}) |
TestCall(true, function(x, y) { |
- "use strict"; |
- receiver = this; return x + y |
+ "use strict" |
+ receiver = this |
+ return x + y |
}) |
-TestCall(false, Proxy.createFunction({}, function(x, y) { |
- receiver = this; return x + y |
+TestCall(false, function() { |
+ receiver = this; return arguments[0] + arguments[1] |
+}) |
+ |
+TestCall(false, Proxy.createFunction(handler, function(x, y) { |
+ receiver = this |
+ return x + y |
})) |
-TestCall(true, Proxy.createFunction({}, function(x, y) { |
- "use strict"; |
- receiver = this; return x + y |
+TestCall(true, Proxy.createFunction(handler, function(x, y) { |
+ "use strict" |
+ receiver = this |
+ return x + y |
})) |
-TestCall(false, CreateFrozen({}, function(x, y) { |
- receiver = this; return x + y |
+TestCall(false, CreateFrozen(handler, function(x, y) { |
+ receiver = this |
+ return x + y |
})) |
+ |
+// Using intrinsics as call traps. |
+ |
+function TestCallIntrinsic(type, callTrap) { |
+ var f = Proxy.createFunction({}, callTrap) |
+ var x = f() |
+ assertTrue(typeof x == type) |
+} |
+ |
+TestCallIntrinsic("boolean", Boolean) |
+TestCallIntrinsic("number", Number) |
+TestCallIntrinsic("string", String) |
+TestCallIntrinsic("object", Object) |
+TestCallIntrinsic("function", Function) |
+ |
+ |
+ |
+// Throwing from call trap. |
+ |
function TestCallThrow(callTrap) { |
var f = Proxy.createFunction({}, callTrap) |
assertThrows(function(){ f(11) }, "myexn") |
+ assertThrows(function(){ ({x: f}).x(11) }, "myexn") |
+ assertThrows(function(){ ({x: f})["x"](11) }, "myexn") |
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn") |
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn") |
var f = CreateFrozen({}, callTrap) |
assertThrows(function(){ f(11) }, "myexn") |
+ assertThrows(function(){ ({x: f}).x(11) }, "myexn") |
+ assertThrows(function(){ ({x: f})["x"](11) }, "myexn") |
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn") |
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn") |
} |
@@ -137,24 +230,48 @@ |
var receiver |
var handlerWithPrototype = { |
- fix: function() { return {prototype: prototype} }, |
- get: function(r, n) { assertEquals("prototype", n); return prototype } |
+ fix: function() { return { prototype: { value: prototype } }; }, |
+ get: function(r, n) { |
+ if (n == "length") return 2; |
+ assertEquals("prototype", n); |
+ return prototype; |
+ } |
} |
var handlerSansPrototype = { |
- fix: function() { return {} }, |
- get: function(r, n) { assertEquals("prototype", n); return undefined } |
+ fix: function() { return { length: { value: 2 } } }, |
+ get: function(r, n) { |
+ if (n == "length") return 2; |
+ assertEquals("prototype", n); |
+ return undefined; |
+ } |
} |
-function ReturnUndef(x, y) { "use strict"; receiver = this; this.sum = x + y } |
-function ReturnThis(x, y) { "use strict"; receiver = this; this.sum = x + y; return this } |
-function ReturnNew(x, y) { "use strict"; receiver = this; return {sum: x + y} } |
+function ReturnUndef(x, y) { |
+ "use strict"; |
+ receiver = this; |
+ this.sum = x + y; |
+} |
+ |
+function ReturnThis(x, y) { |
+ "use strict"; |
+ receiver = this; |
+ this.sum = x + y; |
+ return this; |
+} |
+ |
+function ReturnNew(x, y) { |
+ "use strict"; |
+ receiver = this; |
+ return {sum: x + y}; |
+} |
+ |
function ReturnNewWithProto(x, y) { |
"use strict"; |
receiver = this; |
- var result = Object.create(prototype) |
- result.sum = x + y |
- return result |
+ var result = Object.create(prototype); |
+ result.sum = x + y; |
+ return result; |
} |
function TestConstruct(proto, constructTrap) { |
@@ -165,15 +282,13 @@ |
function TestConstruct2(proto, constructTrap, handler) { |
var f = Proxy.createFunction(handler, function() {}, constructTrap) |
var o = new f(11, 31) |
- // TODO(rossberg): doesn't hold, due to unrelated bug. |
- // assertEquals(undefined, receiver) |
+ assertEquals(undefined, receiver) |
assertEquals(42, o.sum) |
assertSame(proto, Object.getPrototypeOf(o)) |
var f = CreateFrozen(handler, function() {}, constructTrap) |
var o = new f(11, 32) |
- // TODO(rossberg): doesn't hold, due to unrelated bug. |
- // assertEquals(undefined, receiver) |
+ assertEquals(undefined, receiver) |
assertEquals(43, o.sum) |
assertSame(proto, Object.getPrototypeOf(o)) |
} |
@@ -181,13 +296,16 @@ |
TestConstruct(Object.prototype, ReturnNew) |
TestConstruct(prototype, ReturnNewWithProto) |
-TestConstruct(Object.prototype, Proxy.createFunction({}, ReturnNew)) |
-TestConstruct(prototype, Proxy.createFunction({}, ReturnNewWithProto)) |
+TestConstruct(Object.prototype, Proxy.createFunction(handler, ReturnNew)) |
+TestConstruct(prototype, Proxy.createFunction(handler, ReturnNewWithProto)) |
-TestConstruct(Object.prototype, CreateFrozen({}, ReturnNew)) |
-TestConstruct(prototype, CreateFrozen({}, ReturnNewWithProto)) |
+TestConstruct(Object.prototype, CreateFrozen(handler, ReturnNew)) |
+TestConstruct(prototype, CreateFrozen(handler, ReturnNewWithProto)) |
+ |
+// Construction with derived construct trap. |
+ |
function TestConstructFromCall(proto, returnsThis, callTrap) { |
TestConstructFromCall2(proto, returnsThis, callTrap, handlerWithPrototype) |
TestConstructFromCall2(proto, returnsThis, callTrap, handlerSansPrototype) |
@@ -212,10 +330,14 @@ |
TestConstructFromCall(Object.prototype, false, ReturnNew) |
TestConstructFromCall(prototype, false, ReturnNewWithProto) |
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnUndef)) |
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnThis)) |
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction({}, ReturnNew)) |
-TestConstructFromCall(prototype, false, Proxy.createFunction({}, ReturnNewWithProto)) |
+TestConstructFromCall(Object.prototype, true, |
+ Proxy.createFunction(handler, ReturnUndef)) |
+TestConstructFromCall(Object.prototype, true, |
+ Proxy.createFunction(handler, ReturnThis)) |
+TestConstructFromCall(Object.prototype, false, |
+ Proxy.createFunction(handler, ReturnNew)) |
+TestConstructFromCall(prototype, false, |
+ Proxy.createFunction(handler, ReturnNewWithProto)) |
TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnUndef)) |
TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnThis)) |
@@ -232,26 +354,44 @@ |
TestConstructFromCall(Object.prototype, false, ReturnNew) |
TestConstructFromCall(prototype, false, ReturnNewWithProto) |
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnUndef)) |
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnThis)) |
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction({}, ReturnNew)) |
-TestConstructFromCall(prototype, false, Proxy.createFunction({}, ReturnNewWithProto)) |
+TestConstructFromCall(Object.prototype, true, |
+ Proxy.createFunction(handler, ReturnUndef)) |
+TestConstructFromCall(Object.prototype, true, |
+ Proxy.createFunction(handler, ReturnThis)) |
+TestConstructFromCall(Object.prototype, false, |
+ Proxy.createFunction(handler, ReturnNew)) |
+TestConstructFromCall(prototype, false, |
+ Proxy.createFunction(handler, ReturnNewWithProto)) |
-TestConstructFromCall(prototype, true, Proxy.createFunction(handlerWithPrototype, ReturnUndef)) |
-TestConstructFromCall(prototype, true, Proxy.createFunction(handlerWithPrototype, ReturnThis)) |
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction(handlerWithPrototype, ReturnNew)) |
-TestConstructFromCall(prototype, false, Proxy.createFunction(handlerWithPrototype, ReturnNewWithProto)) |
+TestConstructFromCall(prototype, true, |
+ Proxy.createFunction(handlerWithPrototype, ReturnUndef)) |
+TestConstructFromCall(prototype, true, |
+ Proxy.createFunction(handlerWithPrototype, ReturnThis)) |
+TestConstructFromCall(Object.prototype, false, |
+ Proxy.createFunction(handlerWithPrototype, ReturnNew)) |
+TestConstructFromCall(prototype, false, |
+ Proxy.createFunction(handlerWithPrototype, |
+ ReturnNewWithProto)) |
-TestConstructFromCall(prototype, true, CreateFrozen(handlerWithPrototype, ReturnUndef)) |
-TestConstructFromCall(prototype, true, CreateFrozen(handlerWithPrototype, ReturnThis)) |
-TestConstructFromCall(Object.prototype, false, CreateFrozen(handlerWithPrototype, ReturnNew)) |
-TestConstructFromCall(prototype, false, CreateFrozen(handlerWithPrototype, ReturnNewWithProto)) |
+TestConstructFromCall(prototype, true, |
+ CreateFrozen(handlerWithPrototype, ReturnUndef)) |
+TestConstructFromCall(prototype, true, |
+ CreateFrozen(handlerWithPrototype, ReturnThis)) |
+TestConstructFromCall(Object.prototype, false, |
+ CreateFrozen(handlerWithPrototype, ReturnNew)) |
+TestConstructFromCall(prototype, false, |
+ CreateFrozen(handlerWithPrototype, ReturnNewWithProto)) |
+ |
+// Throwing from the construct trap. |
+ |
function TestConstructThrow(trap) { |
- TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}}, trap)) |
- TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}}, |
- function() {}, trap)) |
+ TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} }, |
+ trap)) |
+ TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} }, |
+ function() {}, |
+ trap)) |
} |
function TestConstructThrow2(f) { |
@@ -266,13 +406,13 @@ |
-// Getters and setters. |
+// Using function proxies as getters and setters. |
var value |
var receiver |
function TestAccessorCall(getterCallTrap, setterCallTrap) { |
- var handler = {fix: function() { return {} }} |
+ var handler = { fix: function() { return {} } } |
var pgetter = Proxy.createFunction(handler, getterCallTrap) |
var psetter = Proxy.createFunction(handler, setterCallTrap) |