From 6add3222edf45585b56677c7d3c3577fc82530ba Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Tue, 20 Nov 2012 14:45:21 +0000 Subject: [PATCH] Object.observe: Add test case covering most special cases. Things not working yet are currently blacklisted in the test (see TODOs). R=verwaest@chromium.org BUG= Review URL: https://codereview.chromium.org/11377157 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13016 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- test/mjsunit/harmony/object-observe.js | 157 ++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js index 922a5f3dc..26d097ece 100644 --- a/test/mjsunit/harmony/object-observe.js +++ b/test/mjsunit/harmony/object-observe.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-observation +// Flags: --harmony-observation --harmony-proxies --harmony-collections var allObservers = []; function reset() { @@ -56,7 +56,7 @@ function createObserver() { assertCallbackRecords: function(recs) { this.assertRecordCount(recs.length); for (var i = 0; i < recs.length; i++) { - print(i, JSON.stringify(this.records[i]), JSON.stringify(recs[i])) + print(i, JSON.stringify(this.records[i]), JSON.stringify(recs[i])); assertSame(this.records[i].object, recs[i].object); assertEquals('string', typeof recs[i].type); assertPropertiesEqual(this.records[i], recs[i]); @@ -368,6 +368,159 @@ observer.assertCallbackRecords([ { object: obj, name: "1", type: "new" }, ]); + +// Test all kinds of objects generically. +function TestObserveConfigurable(obj, prop) { + reset(); + obj[prop] = 1; + Object.observe(obj, observer.callback); + obj[prop] = 2; + obj[prop] = 3; + delete obj[prop]; + obj[prop] = 4; + obj[prop] = 4; // ignored + obj[prop] = 5; + Object.defineProperty(obj, prop, {value: 6}); + Object.defineProperty(obj, prop, {writable: false}); + obj[prop] = 7; // ignored + Object.defineProperty(obj, prop, {value: 8}); + Object.defineProperty(obj, prop, {value: 7, writable: true}); + Object.defineProperty(obj, prop, {get: function() {}}); + Object.defineProperty(obj, prop, {get: function() {}}); + delete obj[prop]; + delete obj[prop]; + Object.defineProperty(obj, prop, {get: function() {}, configurable: true}); + Object.defineProperty(obj, prop, {value: 9, writable: true}); + obj[prop] = 10; + delete obj[prop]; + Object.defineProperty(obj, prop, {value: 11, configurable: true}); + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: obj, name: prop, type: "updated", oldValue: 1 }, + { object: obj, name: prop, type: "updated", oldValue: 2 }, + { object: obj, name: prop, type: "deleted", oldValue: 3 }, + { object: obj, name: prop, type: "new" }, + { object: obj, name: prop, type: "updated", oldValue: 4 }, + { object: obj, name: prop, type: "updated", oldValue: 5 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 6 }, + { object: obj, name: prop, type: "updated", oldValue: 6 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 8 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 7 }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "deleted" }, + { object: obj, name: prop, type: "new" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "updated", oldValue: 9 }, + { object: obj, name: prop, type: "deleted", oldValue: 10 }, + { object: obj, name: prop, type: "new" }, + ]); + Object.unobserve(obj, observer.callback); + delete obj[prop]; +} + +function TestObserveNonConfigurable(obj, prop) { + reset(); + obj[prop] = 1; + Object.observe(obj, observer.callback); + obj[prop] = 4; + obj[prop] = 4; // ignored + obj[prop] = 5; + Object.defineProperty(obj, prop, {value: 6}); + Object.defineProperty(obj, prop, {value: 6}); // ignored + Object.defineProperty(obj, prop, {writable: false}); + obj[prop] = 7; // ignored + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: obj, name: prop, type: "updated", oldValue: 1 }, + { object: obj, name: prop, type: "updated", oldValue: 4 }, + { object: obj, name: prop, type: "updated", oldValue: 5 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 6 }, + ]); + Object.unobserve(obj, observer.callback); +} + +function createProxy(create, x) { + var handler = { + getPropertyDescriptor: function(k) { + return Object.getOwnPropertyDescriptor(this.target, k); + }, + getOwnPropertyDescriptor: function(k) { + return Object.getOwnPropertyDescriptor(this.target, k); + }, + defineProperty: function(k, desc) { + var x = Object.defineProperty(this.target, k, desc); + Object.deliverChangeRecords(this.callback); + return x; + }, + delete: function(k) { + var x = delete this.target[k]; + Object.deliverChangeRecords(this.callback); + return x; + }, + getPropertyNames: function() { + return Object.getOwnPropertyNames(this.target); + }, + target: {isProxy: true}, + callback: function(changeRecords) { + print("callback", JSON.stringify(handler.proxy), JSON.stringify(got)); + for (var i in changeRecords) { + var got = changeRecords[i]; + var change = {object: handler.proxy, name: got.name, type: got.type}; + if ("oldValue" in got) change.oldValue = got.oldValue; + Object.getNotifier(handler.proxy).notify(change); + } + }, + }; + Object.observe(handler.target, handler.callback); + return handler.proxy = create(handler, x); +} + +var objects = [ + {}, + [], + this, // global object + function(){}, + (function(){ return arguments })(), + (function(){ "use strict"; return arguments })(), + Object(1), Object(true), Object("bla"), + new Date(), + Object, Function, Date, RegExp, + new Set, new Map, new WeakMap, + new ArrayBuffer(10), new Int32Array(5), + createProxy(Proxy.create, null), + createProxy(Proxy.createFunction, function(){}), +]; +var properties = ["a", "1", 1, "length", "prototype"]; + +// Cases that yield non-standard results. +// TODO(observe): ...or don't work yet. +function blacklisted(obj, prop) { + return (obj instanceof Array && prop == 1) || + (obj instanceof Int32Array && prop == 1) || + (obj instanceof Int32Array && prop === "length") || + // TODO(observe): oldValue when deleting/reconfiguring indexed accessor + prop == 1 || + // TODO(observe): oldValue when reconfiguring array length + (obj instanceof Array && prop === "length") || + // TODO(observe): prototype property on functions + (obj instanceof Function && prop === "prototype") || + // TODO(observe): global object + obj === this; +} + +for (var i in objects) for (var j in properties) { + var obj = objects[i]; + var prop = properties[j]; + if (blacklisted(obj, prop)) continue; + var desc = Object.getOwnPropertyDescriptor(obj, prop); + print("***", typeof obj, JSON.stringify(obj), prop); + if (!desc || desc.configurable) + TestObserveConfigurable(obj, prop); + else if (desc.writable) + TestObserveNonConfigurable(obj, prop); +} + + // Observing array length (including truncation) reset(); var arr = ['a', 'b', 'c', 'd']; -- 2.34.1