Chromium Code Reviews| Index: test/mjsunit/harmony/object-observe.js |
| diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js |
| index dbdf84848d14e228e4a11a5ff4df4e6fd5a0cbcd..9ab5df9c9177fdf7ba3c8df661a7a7262a36302c 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 |
| var allObservers = []; |
| function reset() { |
| @@ -56,6 +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])); |
|
rafaelw
2012/11/20 05:11:07
did you intend to leave this in?
rossberg
2012/11/20 10:34:27
Yes. I was taking this in and out so many times in
|
| assertSame(this.records[i].object, recs[i].object); |
| assertEquals('string', typeof recs[i].type); |
| assertPropertiesEqual(this.records[i], recs[i]); |
| @@ -349,6 +350,162 @@ 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) { |
| + var x = Object.getOwnPropertyDescriptor(this.target, k); |
| + Object.deliverChangeRecords(this.callback); |
|
rafaelw
2012/11/20 05:11:07
In what case will this generate a changeRecord?
rossberg
2012/11/20 10:34:27
You are right, dumb copy & paste. Shouldn't be nee
|
| + return x; |
| + }, |
| + getOwnPropertyDescriptor: function(k) { |
| + var x = Object.getOwnPropertyDescriptor(this.target, k); |
| + Object.deliverChangeRecords(this.callback); |
|
rafaelw
2012/11/20 05:11:07
same question?
rossberg
2012/11/20 10:34:27
Ditto.
|
| + return x; |
| + }, |
| + defineProperty: function(k, desc) { |
| + var x = Object.defineProperty(this.target, k, desc); |
|
rafaelw
2012/11/20 05:11:07
how much of direct proxies are implemented? i woul
rossberg
2012/11/20 10:34:27
'set' is a derived trap in the old semantics, whic
|
| + 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 ArrayBuffer(10), new Int32Array(5), |
|
rafaelw
2012/11/20 05:11:07
new Map, new Set, new WeakMap?
rossberg
2012/11/20 10:34:27
Done.
|
| + 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']; |