michael@0: /* michael@0: * Check the order of splice's internal operations, because the ordering is michael@0: * visible externally. michael@0: */ michael@0: michael@0: function handlerMaker(obj, expected_exceptions) { michael@0: var order = []; michael@0: function note(trap, name) michael@0: { michael@0: order.push(trap + '-' + name); michael@0: if (expected_exceptions[trap] === name) { michael@0: throw ("fail"); michael@0: } michael@0: } michael@0: michael@0: return [{ michael@0: /* this is the only trap we care about */ michael@0: delete: function(name) { michael@0: note("del", name); michael@0: return delete obj[name]; michael@0: }, michael@0: michael@0: // Fundamental traps michael@0: getOwnPropertyDescriptor: function(name) { michael@0: var desc = Object.getOwnPropertyDescriptor(obj, name); michael@0: // a trapping proxy's properties must always be configurable michael@0: if (desc !== undefined) michael@0: desc.configurable = true; michael@0: return desc; michael@0: }, michael@0: getPropertyDescriptor: function(name) { michael@0: var desc = Object.getPropertyDescriptor(obj, name); // not in ES5 michael@0: // a trapping proxy's properties must always be configurable michael@0: if (desc !== undefined) michael@0: desc.configurable = true; michael@0: return desc; michael@0: }, michael@0: getOwnPropertyNames: function() { michael@0: return Object.getOwnPropertyNames(obj); michael@0: }, michael@0: getPropertyNames: function() { michael@0: return Object.getPropertyNames(obj); // not in ES5 michael@0: }, michael@0: defineProperty: function(name, desc) { michael@0: note("def", name); michael@0: Object.defineProperty(obj, name, desc); michael@0: }, michael@0: fix: function() { michael@0: if (Object.isFrozen(obj)) { michael@0: return Object.getOwnPropertyNames(obj).map(function(name) { michael@0: return Object.getOwnPropertyDescriptor(obj, name); michael@0: }); michael@0: } michael@0: // As long as obj is not frozen, the proxy won't allow itself to be fixed michael@0: return undefined; // will cause a TypeError to be thrown michael@0: }, michael@0: michael@0: // derived traps michael@0: has: function(name) { michael@0: note("has", name); michael@0: return name in obj; michael@0: }, michael@0: hasOwn: function(name) { return Object.prototype.hasOwnProperty.call(obj, name); }, michael@0: get: function(receiver, name) { michael@0: note("get", name); michael@0: return obj[name]; michael@0: }, michael@0: set: function(receiver, name, val) { michael@0: note("set", name); michael@0: obj[name] = val; michael@0: return true; // bad behavior when set fails in non-strict mode michael@0: }, michael@0: enumerate: function() { michael@0: var result = []; michael@0: for (name in obj) michael@0: result.push(name); michael@0: return result; michael@0: }, michael@0: keys: function() { return Object.keys(obj) } michael@0: }, order]; michael@0: } michael@0: michael@0: // arr: the array to splice michael@0: // expected_order: the expected order of operations on arr, stringified michael@0: function check_splice_proxy(arr, expected_order, expected_exceptions, expected_array, expected_result) { michael@0: print (arr); michael@0: var [handler, store] = handlerMaker(arr, expected_exceptions); michael@0: var proxy = Proxy.create(handler); michael@0: michael@0: try { michael@0: var args = Array.prototype.slice.call(arguments, 5); michael@0: var result = Array.prototype.splice.apply(proxy, args); michael@0: assertEq(Object.keys(expected_exceptions).length, 0); michael@0: } catch (e) { michael@0: assertEq(Object.keys(expected_exceptions).length > 0, true); michael@0: } michael@0: michael@0: // check the order of the property accesses, etc michael@0: assertEq(store.toString(), expected_order); michael@0: michael@0: // The deleted elements are returned in an object that's always an Array. michael@0: assertEq(Array.isArray(result) || result === undefined, true); michael@0: michael@0: // check the return value michael@0: for (var i in expected_result) { michael@0: assertEq(result[i], expected_result[i]); michael@0: } michael@0: for (var i in result) { michael@0: assertEq(result[i], expected_result[i]); michael@0: } michael@0: michael@0: // check the value of arr michael@0: for (var i in expected_array) { michael@0: assertEq(arr[i], expected_array[i]); michael@0: } michael@0: for (var i in arr) { michael@0: assertEq(arr[i], expected_array[i]); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: // Shrinking array michael@0: check_splice_proxy( michael@0: [10,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4,get-4,set-1,has-5,get-5,set-2," + michael@0: "del-5,del-4,del-3," + michael@0: "set-length", michael@0: {}, michael@0: [3,4,5], michael@0: [10,1,2], michael@0: 0, 3 michael@0: ); michael@0: michael@0: // Growing array michael@0: check_splice_proxy( michael@0: [11,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-9,has-4,get-4,set-8,has-3,get-3,set-7," + michael@0: "set-0,set-1,set-2,set-3,set-4,set-5,set-6," + michael@0: "set-length", michael@0: {}, michael@0: [9,9,9,9,9,9,9,3,4,5], michael@0: [11,1,2], michael@0: 0, 3, 9, 9, 9, 9, 9, 9, 9 michael@0: ); michael@0: michael@0: // Same sized array michael@0: check_splice_proxy( michael@0: [12,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "set-0,set-1,set-2," + michael@0: "set-length", michael@0: {}, michael@0: [9,9,9,3,4,5], michael@0: [12,1,2], michael@0: 0, 3, 9, 9, 9 michael@0: ); michael@0: michael@0: michael@0: /* michael@0: * Check that if we fail at a particular step in the algorithm, we don't michael@0: * continue with the algorithm beyond that step. michael@0: */ michael@0: michael@0: michael@0: // Step 3: fail when getting length michael@0: check_splice_proxy( michael@0: [13,1,2,3,4,5], michael@0: "get-length", michael@0: {get: 'length'}, michael@0: [13,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3, 9, 9, 9 michael@0: ); michael@0: michael@0: // Step 9b: fail when [[HasProperty]] michael@0: check_splice_proxy( michael@0: [14,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1", michael@0: {has: '1'}, michael@0: [14,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3, 9, 9, 9 michael@0: ); michael@0: michael@0: // Step 9c(i): fail when [[Get]] michael@0: check_splice_proxy( michael@0: [15,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1", michael@0: {get: '1'}, michael@0: [15,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3, 9, 9, 9 michael@0: ); michael@0: michael@0: // Step 12b(iii): fail when [[HasProperty]] michael@0: check_splice_proxy( michael@0: [16,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4", michael@0: {has: '4'}, michael@0: [3,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3 michael@0: ); michael@0: michael@0: michael@0: // Step 12b(iv)1: fail when [[Get]] michael@0: check_splice_proxy( michael@0: [17,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4,get-4", michael@0: {get: '4'}, michael@0: [3,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3 michael@0: ); michael@0: michael@0: michael@0: // Step 12b(iv)2: fail when [[Put]] michael@0: check_splice_proxy( michael@0: [18,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4,get-4,set-1", michael@0: {set: '1'}, michael@0: [3,1,2,3,4,5], michael@0: undefined, michael@0: 0, 3 michael@0: ); michael@0: michael@0: // Step 12b(v)1: fail when [[Delete]] michael@0: check_splice_proxy( michael@0: [19,1,2,3,,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4,del-1", michael@0: {del: '1'}, michael@0: [3,1,2,3,,5], michael@0: undefined, michael@0: 0, 3 michael@0: ); michael@0: michael@0: // Step 12d(i): fail when [[Delete]] michael@0: check_splice_proxy( michael@0: [20,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-3,get-3,set-0,has-4,get-4,set-1,has-5,get-5,set-2," + michael@0: "del-5,del-4", michael@0: {del: '4'}, michael@0: [3,4,5,3,4], michael@0: undefined, michael@0: 0, 3 michael@0: ); michael@0: michael@0: // Step 13b(iii): fail when [[HasProperty]] michael@0: check_splice_proxy( michael@0: [21,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-8,has-4", michael@0: {has: '4'}, michael@0: [21,1,2,3,4,5,,,5], michael@0: undefined, michael@0: 0, 3, 9,9,9,9,9,9 michael@0: ); michael@0: michael@0: michael@0: // Step 13b(iv)1: fail when [[Get]] michael@0: check_splice_proxy( michael@0: [22,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-8,has-4,get-4", michael@0: {get: '4'}, michael@0: [22,1,2,3,4,5,,,5], michael@0: undefined, michael@0: 0, 3, 9,9,9,9,9,9 michael@0: ); michael@0: michael@0: michael@0: // Step 13b(iv)2: fail when [[Put]] michael@0: check_splice_proxy( michael@0: [23,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-8,has-4,get-4,set-7", michael@0: {set: '7'}, michael@0: [23,1,2,3,4,5,,,5], michael@0: undefined, michael@0: 0, 3, 9,9,9,9,9,9 michael@0: ); michael@0: michael@0: // Step 13b(v)1: fail when [[Delete]] michael@0: check_splice_proxy( michael@0: [24,1,2,3,,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-8,has-4,del-7", michael@0: {del: '7'}, michael@0: [24,1,2,3,,5,,,5], michael@0: undefined, michael@0: 0, 3, 9,9,9,9,9,9 michael@0: ); michael@0: michael@0: // Step 15b: fail when [[Put]] michael@0: check_splice_proxy( michael@0: [25,1,2,3,4,5], michael@0: "get-length," + michael@0: "has-0,get-0,has-1,get-1,has-2,get-2," + michael@0: "has-5,get-5,set-8,has-4,get-4,set-7,has-3,get-3,set-6," + michael@0: "set-0,set-1,set-2", michael@0: {set: '2'}, michael@0: [9,9,2,3,4,5,3,4,5], michael@0: undefined, michael@0: 0, 3, 9,9,9,9,9,9 michael@0: );