Index: test/mjsunit/harmony/proxies.js |
=================================================================== |
--- test/mjsunit/harmony/proxies.js (revision 9531) |
+++ test/mjsunit/harmony/proxies.js (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright 2008 the V8 project authors. All rights reserved. |
+// Copyright 2011 the V8 project authors. All rights reserved. |
// Redistribution and use in source and binary forms, with or without |
// modification, are permitted provided that the following conditions are |
// met: |
@@ -28,9 +28,7 @@ |
// Flags: --harmony-proxies |
-// TODO(rossberg): for-in for proxies not implemented. |
-// TODO(rossberg): inheritance from proxies not implemented. |
-// TODO(rossberg): function proxies as constructors not implemented. |
+// TODO(rossberg): for-in not implemented on proxies. |
// Helper. |
@@ -41,8 +39,93 @@ |
} |
-// Getters. |
+// Getting property descriptors (Object.getOwnPropertyDescriptor). |
+ |
+var key |
+ |
+function TestGetOwnProperty(handler) { |
+ TestWithProxies(TestGetOwnProperty2, handler) |
+} |
+ |
+function TestGetOwnProperty2(handler, create) { |
+ var p = create(handler) |
+ assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value) |
+ assertEquals("a", key) |
+ assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value) |
+ assertEquals("99", key) |
+} |
+ |
+TestGetOwnProperty({ |
+ getOwnPropertyDescriptor: function(k) { |
+ key = k |
+ return {value: 42, configurable: true} |
+ } |
+}) |
+ |
+TestGetOwnProperty({ |
+ getOwnPropertyDescriptor: function(k) { |
+ return this.getOwnPropertyDescriptor2(k) |
+ }, |
+ getOwnPropertyDescriptor2: function(k) { |
+ key = k |
+ return {value: 42, configurable: true} |
+ } |
+}) |
+ |
+TestGetOwnProperty({ |
+ getOwnPropertyDescriptor: function(k) { |
+ key = k |
+ return {get value() { return 42 }, get configurable() { return true }} |
+ } |
+}) |
+ |
+TestGetOwnProperty(Proxy.create({ |
+ get: function(pr, pk) { |
+ return function(k) { key = k; return {value: 42, configurable: true} } |
+ } |
+})) |
+ |
+ |
+function TestGetOwnPropertyThrow(handler) { |
+ TestWithProxies(TestGetOwnPropertyThrow2, handler) |
+} |
+ |
+function TestGetOwnPropertyThrow2(handler, create) { |
+ var p = create(handler) |
+ assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn") |
+ assertThrows(function(){ Object.getOwnPropertyDescriptor(p, 77) }, "myexn") |
+} |
+ |
+TestGetOwnPropertyThrow({ |
+ getOwnPropertyDescriptor: function(k) { throw "myexn" } |
+}) |
+ |
+TestGetOwnPropertyThrow({ |
+ getOwnPropertyDescriptor: function(k) { |
+ return this.getPropertyDescriptor2(k) |
+ }, |
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" } |
+}) |
+ |
+TestGetOwnPropertyThrow({ |
+ getOwnPropertyDescriptor: function(k) { |
+ return {get value() { throw "myexn" }} |
+ } |
+}) |
+ |
+TestGetOwnPropertyThrow(Proxy.create({ |
+ get: function(pr, pk) { |
+ return function(k) { throw "myexn" } |
+ } |
+})) |
+ |
+ |
+ |
+// Getters (dot, brackets). |
+ |
+var key |
+ |
function TestGet(handler) { |
TestWithProxies(TestGet2, handler) |
} |
@@ -50,48 +133,56 @@ |
function TestGet2(handler, create) { |
var p = create(handler) |
assertEquals(42, p.a) |
+ assertEquals("a", key) |
assertEquals(42, p["b"]) |
+ assertEquals("b", key) |
+ assertEquals(42, p[99]) |
+ assertEquals("99", key) |
- // TODO(rossberg): inheritance from proxies not yet implemented. |
- // var o = Object.create(p, {x: {value: 88}}) |
- // assertEquals(42, o.a) |
- // assertEquals(42, o["b"]) |
- // assertEquals(88, o.x) |
- // assertEquals(88, o["x"]) |
+ var o = Object.create(p, {x: {value: 88}}) |
+ assertEquals(42, o.a) |
+ assertEquals("a", key) |
+ assertEquals(42, o["b"]) |
+ assertEquals("b", key) |
+ assertEquals(42, o[99]) |
+ assertEquals("99", key) |
+ assertEquals(88, o.x) |
+ assertEquals(88, o["x"]) |
} |
TestGet({ |
- get: function(r, k) { return 42 } |
+ get: function(r, k) { key = k; return 42 } |
}) |
TestGet({ |
get: function(r, k) { return this.get2(r, k) }, |
- get2: function(r, k) { return 42 } |
+ get2: function(r, k) { key = k; return 42 } |
}) |
TestGet({ |
- getPropertyDescriptor: function(k) { return {value: 42} } |
+ getPropertyDescriptor: function(k) { key = k; return {value: 42} } |
}) |
TestGet({ |
getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, |
- getPropertyDescriptor2: function(k) { return {value: 42} } |
+ getPropertyDescriptor2: function(k) { key = k; return {value: 42} } |
}) |
TestGet({ |
getPropertyDescriptor: function(k) { |
+ key = k; |
return {get value() { return 42 }} |
} |
}) |
TestGet({ |
get: undefined, |
- getPropertyDescriptor: function(k) { return {value: 42} } |
+ getPropertyDescriptor: function(k) { key = k; return {value: 42} } |
}) |
TestGet(Proxy.create({ |
get: function(pr, pk) { |
- return function(r, k) { return 42 } |
+ return function(r, k) { key = k; return 42 } |
} |
})) |
@@ -103,11 +194,29 @@ |
function TestGetCall2(handler, create) { |
var p = create(handler) |
assertEquals(55, p.f()) |
+ assertEquals(55, p["f"]()) |
assertEquals(55, p.f("unused", "arguments")) |
assertEquals(55, p.f.call(p)) |
+ assertEquals(55, p["f"].call(p)) |
+ assertEquals(55, p[101].call(p)) |
assertEquals(55, p.withargs(45, 5)) |
assertEquals(55, p.withargs.call(p, 11, 22)) |
assertEquals("6655", "66" + p) // calls p.toString |
+ |
+ var o = Object.create(p, {g: {value: function(x) { return x + 88 }}}) |
+ assertEquals(55, o.f()) |
+ assertEquals(55, o["f"]()) |
+ assertEquals(55, o.f("unused", "arguments")) |
+ assertEquals(55, o.f.call(o)) |
+ assertEquals(55, o.f.call(p)) |
+ assertEquals(55, o["f"].call(p)) |
+ assertEquals(55, o[101].call(p)) |
+ assertEquals(55, o.withargs(45, 5)) |
+ assertEquals(55, o.withargs.call(p, 11, 22)) |
+ assertEquals(90, o.g(2)) |
+ assertEquals(91, o.g.call(o, 3)) |
+ assertEquals(92, o.g.call(p, 4)) |
+ assertEquals("6655", "66" + o) // calls o.toString |
} |
TestGetCall({ |
@@ -172,6 +281,15 @@ |
var p = create(handler) |
assertThrows(function(){ p.a }, "myexn") |
assertThrows(function(){ p["b"] }, "myexn") |
+ assertThrows(function(){ p[3] }, "myexn") |
+ |
+ var o = Object.create(p, {x: {value: 88}, '4': {value: 89}}) |
+ assertThrows(function(){ o.a }, "myexn") |
+ assertThrows(function(){ o["b"] }, "myexn") |
+ assertThrows(function(){ o[3] }, "myexn") |
+ assertEquals(88, o.x) |
+ assertEquals(88, o["x"]) |
+ assertEquals(89, o[4]) |
} |
TestGetThrow({ |
@@ -232,6 +350,9 @@ |
assertEquals(43, p["b"] = 43) |
assertEquals("b", key) |
assertEquals(43, val) |
+ assertEquals(44, p[77] = 44) |
+ assertEquals("77", key) |
+ assertEquals(44, val) |
} |
TestSet({ |
@@ -304,7 +425,6 @@ |
})) |
- |
function TestSetThrow(handler, create) { |
TestWithProxies(TestSetThrow2, handler) |
} |
@@ -313,6 +433,7 @@ |
var p = create(handler) |
assertThrows(function(){ p.a = 42 }, "myexn") |
assertThrows(function(){ p["b"] = 42 }, "myexn") |
+ assertThrows(function(){ p[22] = 42 }, "myexn") |
} |
TestSetThrow({ |
@@ -424,7 +545,91 @@ |
})) |
+var key |
+var val |
+function TestSetForDerived(handler, create) { |
+ TestWithProxies(TestSetForDerived2, handler) |
+} |
+ |
+function TestSetForDerived2(handler, create) { |
+ var p = create(handler) |
+ var o = Object.create(p, {x: {value: 88, writable: true}, |
+ '1': {value: 89, writable: true}}) |
+ |
+ key = "" |
+ assertEquals(48, o.x = 48) |
+ assertEquals("", key) // trap not invoked |
+ assertEquals(48, o.x) |
+ |
+ assertEquals(47, o[1] = 47) |
+ assertEquals("", key) // trap not invoked |
+ assertEquals(47, o[1]) |
+ |
+ assertEquals(49, o.y = 49) |
+ assertEquals("y", key) |
+ assertEquals(49, o.y) |
+ |
+ assertEquals(50, o[2] = 50) |
+ assertEquals("2", key) |
+ assertEquals(50, o[2]) |
+ |
+ assertEquals(44, o.p_writable = 44) |
+ assertEquals("p_writable", key) |
+ assertEquals(44, o.p_writable) |
+ |
+ assertEquals(45, o.p_nonwritable = 45) |
+ assertEquals("p_nonwritable", key) |
+ assertEquals(45, o.p_nonwritable) |
+ |
+ assertEquals(46, o.p_setter = 46) |
+ assertEquals("p_setter", key) |
+ assertEquals(46, val) // written to parent |
+ assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter")) |
+ |
+ val = "" |
+ assertEquals(47, o.p_nosetter = 47) |
+ assertEquals("p_nosetter", key) |
+ assertEquals("", val) // not written at all |
+ assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter")); |
+ |
+ key = "" |
+ assertThrows(function(){ "use strict"; o.p_nosetter = 50 }, TypeError) |
+ assertEquals("p_nosetter", key) |
+ assertEquals("", val) // not written at all |
+ |
+ assertThrows(function(){ o.p_nonconf = 53 }, TypeError) |
+ assertEquals("p_nonconf", key) |
+ |
+ assertThrows(function(){ o.p_throw = 51 }, "myexn") |
+ assertEquals("p_throw", key) |
+ |
+ assertThrows(function(){ o.p_setterthrow = 52 }, "myexn") |
+ assertEquals("p_setterthrow", key) |
+} |
+ |
+TestSetForDerived({ |
+ getOwnPropertyDescriptor: function(k) { |
+ key = k; |
+ switch (k) { |
+ case "p_writable": return {writable: true, configurable: true} |
+ case "p_nonwritable": return {writable: false, configurable: true} |
+ case "p_setter":return {set: function(x) { val = x }, configurable: true} |
+ case "p_nosetter": return {get: function() { return 1 }, configurable: true} |
+ case "p_nonconf":return {} |
+ case "p_throw": throw "myexn" |
+ case "p_setterthrow": return {set: function(x) { throw "myexn" }} |
+ default: return undefined |
+ } |
+ } |
+}) |
+ |
+ |
+// TODO(rossberg): TestSetReject, returning false |
+// TODO(rossberg): TestGetProperty, TestSetProperty |
+ |
+ |
+ |
// Property definition (Object.defineProperty and Object.defineProperties). |
var key |
@@ -453,6 +658,12 @@ |
assertEquals(46, desc.value) |
assertEquals(false, desc.enumerable) |
+ assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false})) |
+ assertEquals("101", key) |
+ assertEquals(2, Object.getOwnPropertyNames(desc).length) |
+ assertEquals(47, desc.value) |
+ assertEquals(false, desc.enumerable) |
+ |
var attributes = {configurable: true, mine: 66, minetoo: 23} |
assertEquals(p, Object.defineProperty(p, "d", attributes)) |
assertEquals("d", key) |
@@ -487,7 +698,7 @@ |
// assertEquals(77, desc.value) |
var props = { |
- 'bla': {}, |
+ '11': {}, |
blub: {get: function() { return true }}, |
'': {get value() { return 20 }}, |
last: {value: 21, configurable: true, mine: "eyes"} |
@@ -527,6 +738,7 @@ |
function TestDefineThrow2(handler, create) { |
var p = create(handler) |
assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn") |
+ assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn") |
// TODO(rossberg): These tests require for-in on proxies. |
// var d1 = create({ |
@@ -579,6 +791,8 @@ |
assertEquals("a", key) |
assertEquals(true, delete p["b"]) |
assertEquals("b", key) |
+ assertEquals(true, delete p[1]) |
+ assertEquals("1", key) |
assertEquals(false, delete p.z1) |
assertEquals("z1", key) |
@@ -591,6 +805,8 @@ |
assertEquals("c", key) |
assertEquals(true, delete p["d"]) |
assertEquals("d", key) |
+ assertEquals(true, delete p[2]) |
+ assertEquals("2", key) |
assertThrows(function(){ delete p.z3 }, TypeError) |
assertEquals("z3", key) |
@@ -623,11 +839,13 @@ |
var p = create(handler) |
assertThrows(function(){ delete p.a }, "myexn") |
assertThrows(function(){ delete p["b"] }, "myexn"); |
+ assertThrows(function(){ delete p[3] }, "myexn"); |
(function() { |
"use strict" |
assertThrows(function(){ delete p.c }, "myexn") |
assertThrows(function(){ delete p["d"] }, "myexn") |
+ assertThrows(function(){ delete p[4] }, "myexn"); |
})() |
} |
@@ -778,6 +996,7 @@ |
assertEquals(0, ("zzz" in p) ? 2 : 0) |
assertEquals(2, !("zzz" in p) ? 2 : 0) |
+ // Test compilation in conditionals. |
if ("b" in p) { |
} else { |
assertTrue(false) |
@@ -830,7 +1049,7 @@ |
}) |
TestIn({ |
- get: undefined, |
+ has: undefined, |
getPropertyDescriptor: function(k) { |
key = k; return k < "z" ? {value: 42} : void 0 |
} |
@@ -850,6 +1069,7 @@ |
function TestInThrow2(handler, create) { |
var p = create(handler) |
assertThrows(function(){ return "a" in o }, "myexn") |
+ assertThrows(function(){ return 99 in o }, "myexn") |
assertThrows(function(){ return !("a" in o) }, "myexn") |
assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn") |
assertThrows(function(){ if ("b" in o) {} }, "myexn") |
@@ -876,7 +1096,7 @@ |
}) |
TestInThrow({ |
- get: undefined, |
+ has: undefined, |
getPropertyDescriptor: function(k) { throw "myexn" } |
}) |
@@ -891,7 +1111,159 @@ |
})) |
+function TestInForDerived(handler) { |
+ TestWithProxies(TestInForDerived2, handler) |
+} |
+function TestInForDerived2(handler, create) { |
+ var p = create(handler) |
+ var o = Object.create(p) |
+ |
+ assertTrue("a" in o) |
+ assertEquals("a", key) |
+ assertTrue(99 in o) |
+ assertEquals("99", key) |
+ assertFalse("z" in o) |
+ assertEquals("z", key) |
+ |
+ assertEquals(2, ("a" in o) ? 2 : 0) |
+ assertEquals(0, !("a" in o) ? 2 : 0) |
+ assertEquals(0, ("zzz" in o) ? 2 : 0) |
+ assertEquals(2, !("zzz" in o) ? 2 : 0) |
+ |
+ if ("b" in o) { |
+ } else { |
+ assertTrue(false) |
+ } |
+ assertEquals("b", key) |
+ |
+ if ("zz" in o) { |
+ assertTrue(false) |
+ } |
+ assertEquals("zz", key) |
+ |
+ if (!("c" in o)) { |
+ assertTrue(false) |
+ } |
+ assertEquals("c", key) |
+ |
+ if (!("zzz" in o)) { |
+ } else { |
+ assertTrue(false) |
+ } |
+ assertEquals("zzz", key) |
+} |
+ |
+TestInForDerived({ |
+ getPropertyDescriptor: function(k) { |
+ key = k; return k < "z" ? {value: 42, configurable: true} : void 0 |
+ } |
+}) |
+ |
+TestInForDerived({ |
+ getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, |
+ getPropertyDescriptor2: function(k) { |
+ key = k; return k < "z" ? {value: 42, configurable: true} : void 0 |
+ } |
+}) |
+ |
+TestInForDerived({ |
+ getPropertyDescriptor: function(k) { |
+ key = k; |
+ return k < "z" ? {get value() { return 42 }, configurable: true} : void 0 |
+ } |
+}) |
+ |
+/* TODO(rossberg): this will work once we implement the newest proposal |
+ * regarding default traps for getPropertyDescriptor. |
+TestInForDerived({ |
+ getOwnPropertyDescriptor: function(k) { |
+ key = k; return k < "z" ? {value: 42, configurable: true} : void 0 |
+ } |
+}) |
+ |
+TestInForDerived({ |
+ getOwnPropertyDescriptor: function(k) { |
+ return this.getOwnPropertyDescriptor2(k) |
+ }, |
+ getOwnPropertyDescriptor2: function(k) { |
+ key = k; return k < "z" ? {value: 42, configurable: true} : void 0 |
+ } |
+}) |
+ |
+TestInForDerived({ |
+ getOwnPropertyDescriptor: function(k) { |
+ key = k; |
+ return k < "z" ? {get value() { return 42 }, configurable: true} : void 0 |
+ } |
+}) |
+*/ |
+ |
+TestInForDerived(Proxy.create({ |
+ get: function(pr, pk) { |
+ return function(k) { |
+ key = k; return k < "z" ? {value: 42, configurable: true} : void 0 |
+ } |
+ } |
+})) |
+ |
+ |
+ |
+// Property descriptor conversion. |
+ |
+var descget |
+ |
+function TestDescriptorGetOrder(handler) { |
+ var p = Proxy.create(handler) |
+ var o = Object.create(p, {b: {value: 0}}) |
+ TestDescriptorGetOrder2(function(n) { return p[n] }, "vV") |
+ TestDescriptorGetOrder2(function(n) { return n in p }, "") |
+ TestDescriptorGetOrder2(function(n) { return o[n] }, "vV") |
+ TestDescriptorGetOrder2(function(n) { return n in o }, "eEcCvVwWgs") |
+} |
+ |
+function TestDescriptorGetOrder2(f, access) { |
+ descget = "" |
+ assertTrue(f("a")) |
+ assertEquals(access, descget) |
+ descget = "" |
+ assertTrue(f(99)) |
+ assertEquals(access, descget) |
+ descget = "" |
+ assertFalse(!!f("z")) |
+ assertEquals("", descget) |
+} |
+ |
+TestDescriptorGetOrder({ |
+ getPropertyDescriptor: function(k) { |
+ if (k >= "z") return void 0 |
+ // Return a proxy as property descriptor, so that we can log accesses. |
+ return Proxy.create({ |
+ get: function(r, attr) { |
+ descget += attr[0].toUpperCase() |
+ return true |
+ }, |
+ has: function(attr) { |
+ descget += attr[0] |
+ switch (attr) { |
+ case "writable": |
+ case "enumerable": |
+ case "configurable": |
+ case "value": |
+ return true |
+ case "get": |
+ case "set": |
+ return false |
+ default: |
+ assertUnreachable() |
+ } |
+ } |
+ }) |
+ } |
+}) |
+ |
+ |
+ |
// Own Properties (Object.prototype.hasOwnProperty). |
var key |
@@ -1006,34 +1378,46 @@ |
// Instanceof (instanceof) |
function TestInstanceof() { |
- var o = {} |
+ var o1 = {} |
var p1 = Proxy.create({}) |
- var p2 = Proxy.create({}, o) |
+ var p2 = Proxy.create({}, o1) |
var p3 = Proxy.create({}, p2) |
+ var o2 = Object.create(p2) |
var f0 = function() {} |
- f0.prototype = o |
+ f0.prototype = o1 |
var f1 = function() {} |
f1.prototype = p1 |
var f2 = function() {} |
f2.prototype = p2 |
+ var f3 = function() {} |
+ f3.prototype = o2 |
- assertTrue(o instanceof Object) |
- assertFalse(o instanceof f0) |
- assertFalse(o instanceof f1) |
- assertFalse(o instanceof f2) |
+ assertTrue(o1 instanceof Object) |
+ assertFalse(o1 instanceof f0) |
+ assertFalse(o1 instanceof f1) |
+ assertFalse(o1 instanceof f2) |
+ assertFalse(o1 instanceof f3) |
assertFalse(p1 instanceof Object) |
assertFalse(p1 instanceof f0) |
assertFalse(p1 instanceof f1) |
assertFalse(p1 instanceof f2) |
+ assertFalse(p1 instanceof f3) |
assertTrue(p2 instanceof Object) |
assertTrue(p2 instanceof f0) |
assertFalse(p2 instanceof f1) |
assertFalse(p2 instanceof f2) |
+ assertFalse(p2 instanceof f3) |
assertTrue(p3 instanceof Object) |
assertTrue(p3 instanceof f0) |
assertFalse(p3 instanceof f1) |
assertTrue(p3 instanceof f2) |
+ assertFalse(p3 instanceof f3) |
+ assertTrue(o2 instanceof Object) |
+ assertTrue(o2 instanceof f0) |
+ assertFalse(o2 instanceof f1) |
+ assertTrue(o2 instanceof f2) |
+ assertFalse(o2 instanceof f3) |
var f = Proxy.createFunction({}, function() {}) |
assertTrue(f instanceof Function) |
@@ -1046,43 +1430,57 @@ |
// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf). |
function TestPrototype() { |
- var o = {} |
+ var o1 = {} |
var p1 = Proxy.create({}) |
- var p2 = Proxy.create({}, o) |
+ var p2 = Proxy.create({}, o1) |
var p3 = Proxy.create({}, p2) |
var p4 = Proxy.create({}, 666) |
+ var o2 = Object.create(p3) |
- assertSame(Object.getPrototypeOf(o), Object.prototype) |
+ assertSame(Object.getPrototypeOf(o1), Object.prototype) |
assertSame(Object.getPrototypeOf(p1), null) |
- assertSame(Object.getPrototypeOf(p2), o) |
+ assertSame(Object.getPrototypeOf(p2), o1) |
assertSame(Object.getPrototypeOf(p3), p2) |
assertSame(Object.getPrototypeOf(p4), null) |
+ assertSame(Object.getPrototypeOf(o2), p3) |
- assertTrue(Object.prototype.isPrototypeOf(o)) |
+ assertTrue(Object.prototype.isPrototypeOf(o1)) |
assertFalse(Object.prototype.isPrototypeOf(p1)) |
assertTrue(Object.prototype.isPrototypeOf(p2)) |
assertTrue(Object.prototype.isPrototypeOf(p3)) |
assertFalse(Object.prototype.isPrototypeOf(p4)) |
- assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o)) |
+ assertTrue(Object.prototype.isPrototypeOf(o2)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1)) |
assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1)) |
assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2)) |
assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3)) |
assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4)) |
- assertFalse(Object.prototype.isPrototypeOf.call(o, o)) |
- assertFalse(Object.prototype.isPrototypeOf.call(o, p1)) |
- assertTrue(Object.prototype.isPrototypeOf.call(o, p2)) |
- assertTrue(Object.prototype.isPrototypeOf.call(o, p3)) |
- assertFalse(Object.prototype.isPrototypeOf.call(o, p4)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o1, o1)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o1, p1)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(o1, p2)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(o1, p3)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o1, p4)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(o1, o2)) |
assertFalse(Object.prototype.isPrototypeOf.call(p1, p1)) |
- assertFalse(Object.prototype.isPrototypeOf.call(p1, o)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(p1, o1)) |
assertFalse(Object.prototype.isPrototypeOf.call(p1, p2)) |
assertFalse(Object.prototype.isPrototypeOf.call(p1, p3)) |
assertFalse(Object.prototype.isPrototypeOf.call(p1, p4)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(p1, o2)) |
assertFalse(Object.prototype.isPrototypeOf.call(p2, p1)) |
assertFalse(Object.prototype.isPrototypeOf.call(p2, p2)) |
assertTrue(Object.prototype.isPrototypeOf.call(p2, p3)) |
assertFalse(Object.prototype.isPrototypeOf.call(p2, p4)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(p2, o2)) |
assertFalse(Object.prototype.isPrototypeOf.call(p3, p2)) |
+ assertTrue(Object.prototype.isPrototypeOf.call(p3, o2)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, o1)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, p1)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, p2)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, p3)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, p4)) |
+ assertFalse(Object.prototype.isPrototypeOf.call(o2, o2)) |
var f = Proxy.createFunction({}, function() {}) |
assertSame(Object.getPrototypeOf(f), Function.prototype) |
@@ -1267,7 +1665,6 @@ |
// Fixing (Object.freeze, Object.seal, Object.preventExtensions, |
// Object.isFrozen, Object.isSealed, Object.isExtensible) |
-// TODO(rossberg): use TestWithProxies to include funciton proxies |
function TestFix(names, handler) { |
var proto = {p: 77} |
var assertFixing = function(o, s, f, e) { |
@@ -1314,19 +1711,27 @@ |
Object.keys(p3).sort()) |
assertEquals(proto, Object.getPrototypeOf(p3)) |
assertEquals(77, p3.p) |
+ |
+ var p = Proxy.create(handler, proto) |
+ var o = Object.create(p) |
+ assertFixing(p, false, false, true) |
+ assertFixing(o, false, false, true) |
+ Object.freeze(o) |
+ assertFixing(p, false, false, true) |
+ assertFixing(o, true, true, false) |
} |
TestFix([], { |
fix: function() { return {} } |
}) |
-TestFix(["a", "b", "c", "d", "zz"], { |
+TestFix(["a", "b", "c", "3", "zz"], { |
fix: function() { |
return { |
a: {value: "a", writable: true, configurable: false, enumerable: true}, |
b: {value: 33, writable: false, configurable: false, enumerable: true}, |
c: {value: 0, writable: true, configurable: true, enumerable: true}, |
- d: {value: true, writable: false, configurable: true, enumerable: true}, |
+ '3': {value: true, writable: false, configurable: true, enumerable: true}, |
zz: {value: 0, enumerable: false} |
} |
} |
@@ -1426,6 +1831,13 @@ |
assertEquals("my_proxy", Object.prototype.toLocaleString.call(f)) |
assertEquals("toString", key) |
assertDoesNotThrow(function(){ Function.prototype.toString.call(f) }) |
+ |
+ var o = Object.create(p) |
+ key = "" |
+ assertEquals("[object Object]", Object.prototype.toString.call(o)) |
+ assertEquals("", key) |
+ assertEquals("my_proxy", Object.prototype.toLocaleString.call(o)) |
+ assertEquals("toString", key) |
} |
TestToString({ |
@@ -1452,6 +1864,10 @@ |
var f = Proxy.createFunction(handler, function() {}) |
assertEquals("[object Function]", Object.prototype.toString.call(f)) |
assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn") |
+ |
+ var o = Object.create(p) |
+ assertEquals("[object Object]", Object.prototype.toString.call(o)) |
+ assertThrows(function(){ Object.prototype.toLocaleString.call(o) }, "myexn") |
} |
TestToStringThrow({ |
@@ -1510,6 +1926,11 @@ |
assertEquals("2", key) |
assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z")) |
assertEquals("z", key) |
+ |
+ var o = Object.create(p) |
+ key = "" |
+ assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a")) |
+ assertEquals("", key) // trap not invoked |
} |
TestIsEnumerable({ |
@@ -1586,23 +2007,30 @@ |
// Calling (call, Function.prototype.call, Function.prototype.apply, |
// Function.prototype.bind). |
-var global = this |
+var global_object = this |
var receiver |
+function CreateFrozen(handler, callTrap, constructTrap) { |
+ if (handler.fix === undefined) handler.fix = function() { return {} } |
+ var f = Proxy.createFunction(handler, callTrap, constructTrap) |
+ Object.freeze(f) |
+ return f |
+} |
+ |
function TestCall(isStrict, callTrap) { |
assertEquals(42, callTrap(5, 37)) |
-// TODO(rossberg): unrelated bug: this does not succeed for optimized code. |
-// assertEquals(isStrict ? undefined : global, receiver) |
+ // TODO(rossberg): unrelated bug: this does not succeed for optimized code: |
+ // assertEquals(isStrict ? undefined : global_object, receiver) |
- var f = Proxy.createFunction({fix: function() { return {} }}, callTrap) |
+ var f = Proxy.createFunction({}, callTrap) |
receiver = 333 |
assertEquals(42, f(11, 31)) |
- assertEquals(isStrict ? undefined : global, receiver) |
+ assertEquals(isStrict ? undefined : global_object, receiver) |
var o = {} |
assertEquals(42, Function.prototype.call.call(f, o, 20, 22)) |
assertEquals(o, receiver) |
assertEquals(43, Function.prototype.call.call(f, null, 20, 23)) |
- assertEquals(isStrict ? null : global, receiver) |
+ assertEquals(isStrict ? null : global_object, receiver) |
assertEquals(44, Function.prototype.call.call(f, 2, 21, 23)) |
assertEquals(2, receiver.valueOf()) |
receiver = 333 |
@@ -1616,11 +2044,11 @@ |
assertEquals(32, Function.prototype.apply.call(ff, {}, [20])) |
assertEquals(o, receiver) |
- Object.freeze(f) |
+ 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) |
+ // TODO(rossberg): unrelated bug: this does not succeed for optimized code. |
+ // assertEquals(isStrict ? undefined : global, receiver) |
receiver = 333 |
assertEquals(42, Function.prototype.call.call(f, o, 20, 22)) |
assertEquals(o, receiver) |
@@ -1653,21 +2081,18 @@ |
receiver = this; return x + y |
})) |
-var p = Proxy.createFunction({fix: function() {return {}}}, function(x, y) { |
+TestCall(false, CreateFrozen({}, function(x, y) { |
receiver = this; return x + y |
-}) |
-TestCall(false, p) |
-Object.freeze(p) |
-TestCall(false, p) |
+})) |
function TestCallThrow(callTrap) { |
- var f = Proxy.createFunction({fix: function() {return {}}}, callTrap) |
+ var f = Proxy.createFunction({}, callTrap) |
assertThrows(function(){ f(11) }, "myexn") |
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn") |
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn") |
- Object.freeze(f) |
+ var f = CreateFrozen({}, callTrap) |
assertThrows(function(){ f(11) }, "myexn") |
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn") |
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn") |
@@ -1675,8 +2100,256 @@ |
TestCallThrow(function() { throw "myexn" }) |
TestCallThrow(Proxy.createFunction({}, function() { throw "myexn" })) |
+TestCallThrow(CreateFrozen({}, function() { throw "myexn" })) |
-var p = Proxy.createFunction( |
- {fix: function() {return {}}}, function() { throw "myexn" }) |
-Object.freeze(p) |
-TestCallThrow(p) |
+ |
+ |
+// Construction (new). |
+ |
+var prototype = {} |
+var receiver |
+ |
+var handlerWithPrototype = { |
+ fix: function() { return {prototype: prototype} }, |
+ get: function(r, n) { assertEquals("prototype", n); return prototype } |
+} |
+ |
+var handlerSansPrototype = { |
+ fix: function() { return {} }, |
+ get: function(r, n) { 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 ReturnNewWithProto(x, y) { |
+ "use strict"; |
+ receiver = this; |
+ var result = Object.create(prototype) |
+ result.sum = x + y |
+ return result |
+} |
+ |
+function TestConstruct(proto, constructTrap) { |
+ TestConstruct2(proto, constructTrap, handlerWithPrototype) |
+ TestConstruct2(proto, constructTrap, handlerSansPrototype) |
+} |
+ |
+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(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(43, o.sum) |
+ assertSame(proto, Object.getPrototypeOf(o)) |
+} |
+ |
+TestConstruct(Object.prototype, ReturnNew) |
+TestConstruct(prototype, ReturnNewWithProto) |
+ |
+TestConstruct(Object.prototype, Proxy.createFunction({}, ReturnNew)) |
+TestConstruct(prototype, Proxy.createFunction({}, ReturnNewWithProto)) |
+ |
+TestConstruct(Object.prototype, CreateFrozen({}, ReturnNew)) |
+TestConstruct(prototype, CreateFrozen({}, ReturnNewWithProto)) |
+ |
+ |
+function TestConstructFromCall(proto, returnsThis, callTrap) { |
+ TestConstructFromCall2(proto, returnsThis, callTrap, handlerWithPrototype) |
+ TestConstructFromCall2(proto, returnsThis, callTrap, handlerSansPrototype) |
+} |
+ |
+function TestConstructFromCall2(proto, returnsThis, callTrap, handler) { |
+ var f = Proxy.createFunction(handler, callTrap) |
+ var o = new f(11, 31) |
+ if (returnsThis) assertEquals(o, receiver) |
+ assertEquals(42, o.sum) |
+ assertSame(proto, Object.getPrototypeOf(o)) |
+ |
+ var f = CreateFrozen(handler, callTrap) |
+ var o = new f(11, 32) |
+ if (returnsThis) assertEquals(o, receiver) |
+ assertEquals(43, o.sum) |
+ assertSame(proto, Object.getPrototypeOf(o)) |
+} |
+ |
+TestConstructFromCall(Object.prototype, true, ReturnUndef) |
+TestConstructFromCall(Object.prototype, true, ReturnThis) |
+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, CreateFrozen({}, ReturnUndef)) |
+TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnThis)) |
+TestConstructFromCall(Object.prototype, false, CreateFrozen({}, ReturnNew)) |
+TestConstructFromCall(prototype, false, CreateFrozen({}, ReturnNewWithProto)) |
+ |
+ReturnUndef.prototype = prototype |
+ReturnThis.prototype = prototype |
+ReturnNew.prototype = prototype |
+ReturnNewWithProto.prototype = prototype |
+ |
+TestConstructFromCall(prototype, true, ReturnUndef) |
+TestConstructFromCall(prototype, true, ReturnThis) |
+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(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)) |
+ |
+ |
+function TestConstructThrow(trap) { |
+ TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}}, trap)) |
+ TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}}, |
+ function() {}, trap)) |
+} |
+ |
+function TestConstructThrow2(f) { |
+ assertThrows(function(){ new f(11) }, "myexn") |
+ Object.freeze(f) |
+ assertThrows(function(){ new f(11) }, "myexn") |
+} |
+ |
+TestConstructThrow(function() { throw "myexn" }) |
+TestConstructThrow(Proxy.createFunction({}, function() { throw "myexn" })) |
+TestConstructThrow(CreateFrozen({}, function() { throw "myexn" })) |
+ |
+ |
+ |
+// Getters and setters. |
+ |
+var value |
+var receiver |
+ |
+function TestAccessorCall(getterCallTrap, setterCallTrap) { |
+ var handler = {fix: function() { return {} }} |
+ var pgetter = Proxy.createFunction(handler, getterCallTrap) |
+ var psetter = Proxy.createFunction(handler, setterCallTrap) |
+ |
+ var o = {} |
+ var oo = Object.create(o) |
+ Object.defineProperty(o, "a", {get: pgetter, set: psetter}) |
+ Object.defineProperty(o, "b", {get: pgetter}) |
+ Object.defineProperty(o, "c", {set: psetter}) |
+ Object.defineProperty(o, "3", {get: pgetter, set: psetter}) |
+ Object.defineProperty(oo, "a", {value: 43}) |
+ |
+ receiver = "" |
+ assertEquals(42, o.a) |
+ assertSame(o, receiver) |
+ receiver = "" |
+ assertEquals(42, o.b) |
+ assertSame(o, receiver) |
+ receiver = "" |
+ assertEquals(undefined, o.c) |
+ assertEquals("", receiver) |
+ receiver = "" |
+ assertEquals(42, o["a"]) |
+ assertSame(o, receiver) |
+ receiver = "" |
+ assertEquals(42, o[3]) |
+ assertSame(o, receiver) |
+ |
+ receiver = "" |
+ assertEquals(43, oo.a) |
+ assertEquals("", receiver) |
+ receiver = "" |
+ assertEquals(42, oo.b) |
+ assertSame(o, receiver) |
+ receiver = "" |
+ assertEquals(undefined, oo.c) |
+ assertEquals("", receiver) |
+ receiver = "" |
+ assertEquals(43, oo["a"]) |
+ assertEquals("", receiver) |
+ receiver = "" |
+ assertEquals(42, oo[3]) |
+ assertSame(o, receiver) |
+ |
+ receiver = "" |
+ assertEquals(50, o.a = 50) |
+ assertSame(o, receiver) |
+ assertEquals(50, value) |
+ receiver = "" |
+ assertEquals(51, o.b = 51) |
+ assertEquals("", receiver) |
+ assertEquals(50, value) // no setter |
+ assertThrows(function() { "use strict"; o.b = 51 }, TypeError) |
+ receiver = "" |
+ assertEquals(52, o.c = 52) |
+ assertSame(o, receiver) |
+ assertEquals(52, value) |
+ receiver = "" |
+ assertEquals(53, o["a"] = 53) |
+ assertSame(o, receiver) |
+ assertEquals(53, value) |
+ receiver = "" |
+ assertEquals(54, o[3] = 54) |
+ assertSame(o, receiver) |
+ assertEquals(54, value) |
+ |
+ value = 0 |
+ receiver = "" |
+ assertEquals(60, oo.a = 60) |
+ assertEquals("", receiver) |
+ assertEquals(0, value) // oo has own 'a' |
+ assertEquals(61, oo.b = 61) |
+ assertSame("", receiver) |
+ assertEquals(0, value) // no setter |
+ assertThrows(function() { "use strict"; oo.b = 61 }, TypeError) |
+ receiver = "" |
+ assertEquals(62, oo.c = 62) |
+ assertSame(oo, receiver) |
+ assertEquals(62, value) |
+ receiver = "" |
+ assertEquals(63, oo["c"] = 63) |
+ assertSame(oo, receiver) |
+ assertEquals(63, value) |
+ receiver = "" |
+ assertEquals(64, oo[3] = 64) |
+ assertSame(oo, receiver) |
+ assertEquals(64, value) |
+} |
+ |
+TestAccessorCall( |
+ function() { receiver = this; return 42 }, |
+ function(x) { receiver = this; value = x } |
+) |
+ |
+TestAccessorCall( |
+ function() { "use strict"; receiver = this; return 42 }, |
+ function(x) { "use strict"; receiver = this; value = x } |
+) |
+ |
+TestAccessorCall( |
+ Proxy.createFunction({}, function() { receiver = this; return 42 }), |
+ Proxy.createFunction({}, function(x) { receiver = this; value = x }) |
+) |
+ |
+TestAccessorCall( |
+ CreateFrozen({}, function() { receiver = this; return 42 }), |
+ CreateFrozen({}, function(x) { receiver = this; value = x }) |
+) |