| // Test that the watch handler is not called recursively for the same object |
| // and property. |
| (function() { |
| var obj1 = {}, obj2 = {}; |
| var handler_entry_count = 0; |
| var handler_exit_count = 0; |
| |
| obj1.watch('x', handler); |
| obj1.watch('y', handler); |
| obj2.watch('x', handler); |
| obj1.x = 1; |
| assertEq(handler_entry_count, 3); |
| assertEq(handler_exit_count, 3); |
| |
| function handler(id) { |
| handler_entry_count++; |
| assertEq(handler_exit_count, 0); |
| switch (true) { |
| case this === obj1 && id === "x": |
| assertEq(handler_entry_count, 1); |
| obj2.x = 3; |
| assertEq(handler_exit_count, 2); |
| break; |
| case this === obj2 && id === "x": |
| assertEq(handler_entry_count, 2); |
| obj1.y = 4; |
| assertEq(handler_exit_count, 1); |
| break; |
| default: |
| assertEq(this, obj1); |
| assertEq(id, "y"); |
| assertEq(handler_entry_count, 3); |
| |
| // We expect no more watch handler invocations |
| obj1.x = 5; |
| obj1.y = 6; |
| obj2.x = 7; |
| assertEq(handler_exit_count, 0); |
| break; |
| } |
| ++handler_exit_count; |
| assertEq(handler_entry_count, 3); |
| } |
| })(); |
| |
| |
| // Test that run-away recursion in watch handlers is properly handled. |
| (function() { |
| var obj = {}; |
| var i = 0; |
| try { |
| handler(); |
| throw new Error("Unreachable"); |
| } catch(e) { |
| assertEq(e instanceof InternalError, true); |
| } |
| |
| function handler() { |
| var prop = "a" + ++i; |
| obj.watch(prop, handler); |
| obj[prop] = 2; |
| } |
| })(); |