| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 assertCalled: function() { | 58 assertCalled: function() { |
| 59 assertEquals(1, this.callbackCount); | 59 assertEquals(1, this.callbackCount); |
| 60 }, | 60 }, |
| 61 assertRecordCount: function(count) { | 61 assertRecordCount: function(count) { |
| 62 this.assertCalled(); | 62 this.assertCalled(); |
| 63 assertEquals(count, this.records.length); | 63 assertEquals(count, this.records.length); |
| 64 }, | 64 }, |
| 65 assertCallbackRecords: function(recs) { | 65 assertCallbackRecords: function(recs) { |
| 66 this.assertRecordCount(recs.length); | 66 this.assertRecordCount(recs.length); |
| 67 for (var i = 0; i < recs.length; i++) { | 67 for (var i = 0; i < recs.length; i++) { |
| 68 if ('name' in recs[i]) | 68 if ('name' in recs[i]) recs[i].name = String(recs[i].name); |
| 69 recs[i].name = String(recs[i].name); | |
| 70 print(i, stringifyNoThrow(this.records[i]), stringifyNoThrow(recs[i])); | 69 print(i, stringifyNoThrow(this.records[i]), stringifyNoThrow(recs[i])); |
| 71 assertSame(this.records[i].object, recs[i].object); | 70 assertSame(this.records[i].object, recs[i].object); |
| 72 assertEquals('string', typeof recs[i].type); | 71 assertEquals('string', typeof recs[i].type); |
| 73 assertPropertiesEqual(this.records[i], recs[i]); | 72 assertPropertiesEqual(this.records[i], recs[i]); |
| 74 } | 73 } |
| 75 } | 74 } |
| 76 }; | 75 }; |
| 77 | 76 |
| 78 observer.callback = function(r) { | 77 observer.callback = function(r) { |
| 79 assertEquals(undefined, this); | 78 assertEquals(undefined, this); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 98 var changeRecordWithAccessor = { type: 'foo' }; | 97 var changeRecordWithAccessor = { type: 'foo' }; |
| 99 var recordCreated = false; | 98 var recordCreated = false; |
| 100 Object.defineProperty(changeRecordWithAccessor, 'name', { | 99 Object.defineProperty(changeRecordWithAccessor, 'name', { |
| 101 get: function() { | 100 get: function() { |
| 102 recordCreated = true; | 101 recordCreated = true; |
| 103 return "bar"; | 102 return "bar"; |
| 104 }, | 103 }, |
| 105 enumerable: true | 104 enumerable: true |
| 106 }) | 105 }) |
| 107 | 106 |
| 107 |
| 108 // Object.observe | 108 // Object.observe |
| 109 assertThrows(function() { Object.observe("non-object", observer.callback); }, Ty
peError); | 109 assertThrows(function() { Object.observe("non-object", observer.callback); }, Ty
peError); |
| 110 assertThrows(function() { Object.observe(obj, nonFunction); }, TypeError); | 110 assertThrows(function() { Object.observe(obj, nonFunction); }, TypeError); |
| 111 assertThrows(function() { Object.observe(obj, frozenFunction); }, TypeError); | 111 assertThrows(function() { Object.observe(obj, frozenFunction); }, TypeError); |
| 112 assertEquals(obj, Object.observe(obj, observer.callback)); | 112 assertEquals(obj, Object.observe(obj, observer.callback)); |
| 113 | 113 |
| 114 |
| 114 // Object.unobserve | 115 // Object.unobserve |
| 115 assertThrows(function() { Object.unobserve(4, observer.callback); }, TypeError); | 116 assertThrows(function() { Object.unobserve(4, observer.callback); }, TypeError); |
| 116 assertThrows(function() { Object.unobserve(obj, nonFunction); }, TypeError); | 117 assertThrows(function() { Object.unobserve(obj, nonFunction); }, TypeError); |
| 117 assertEquals(obj, Object.unobserve(obj, observer.callback)); | 118 assertEquals(obj, Object.unobserve(obj, observer.callback)); |
| 118 | 119 |
| 120 |
| 119 // Object.getNotifier | 121 // Object.getNotifier |
| 120 var notifier = Object.getNotifier(obj); | 122 var notifier = Object.getNotifier(obj); |
| 121 assertSame(notifier, Object.getNotifier(obj)); | 123 assertSame(notifier, Object.getNotifier(obj)); |
| 122 assertEquals(null, Object.getNotifier(Object.freeze({}))); | 124 assertEquals(null, Object.getNotifier(Object.freeze({}))); |
| 123 assertFalse(notifier.hasOwnProperty('notify')); | 125 assertFalse(notifier.hasOwnProperty('notify')); |
| 124 assertEquals([], Object.keys(notifier)); | 126 assertEquals([], Object.keys(notifier)); |
| 125 var notifyDesc = Object.getOwnPropertyDescriptor(notifier.__proto__, 'notify'); | 127 var notifyDesc = Object.getOwnPropertyDescriptor(notifier.__proto__, 'notify'); |
| 126 assertTrue(notifyDesc.configurable); | 128 assertTrue(notifyDesc.configurable); |
| 127 assertTrue(notifyDesc.writable); | 129 assertTrue(notifyDesc.writable); |
| 128 assertFalse(notifyDesc.enumerable); | 130 assertFalse(notifyDesc.enumerable); |
| 129 assertThrows(function() { notifier.notify({}); }, TypeError); | 131 assertThrows(function() { notifier.notify({}); }, TypeError); |
| 130 assertThrows(function() { notifier.notify({ type: 4 }); }, TypeError); | 132 assertThrows(function() { notifier.notify({ type: 4 }); }, TypeError); |
| 131 var notify = notifier.notify; | 133 var notify = notifier.notify; |
| 132 assertThrows(function() { notify.call(undefined, { type: 'a' }); }, TypeError); | 134 assertThrows(function() { notify.call(undefined, { type: 'a' }); }, TypeError); |
| 133 assertThrows(function() { notify.call(null, { type: 'a' }); }, TypeError); | 135 assertThrows(function() { notify.call(null, { type: 'a' }); }, TypeError); |
| 134 assertThrows(function() { notify.call(5, { type: 'a' }); }, TypeError); | 136 assertThrows(function() { notify.call(5, { type: 'a' }); }, TypeError); |
| 135 assertThrows(function() { notify.call('hello', { type: 'a' }); }, TypeError); | 137 assertThrows(function() { notify.call('hello', { type: 'a' }); }, TypeError); |
| 136 assertThrows(function() { notify.call(false, { type: 'a' }); }, TypeError); | 138 assertThrows(function() { notify.call(false, { type: 'a' }); }, TypeError); |
| 137 assertThrows(function() { notify.call({}, { type: 'a' }); }, TypeError); | 139 assertThrows(function() { notify.call({}, { type: 'a' }); }, TypeError); |
| 138 assertFalse(recordCreated); | 140 assertFalse(recordCreated); |
| 139 notifier.notify(changeRecordWithAccessor); | 141 notifier.notify(changeRecordWithAccessor); |
| 140 assertFalse(recordCreated); // not observed yet | 142 assertFalse(recordCreated); // not observed yet |
| 141 | 143 |
| 144 |
| 142 // Object.deliverChangeRecords | 145 // Object.deliverChangeRecords |
| 143 assertThrows(function() { Object.deliverChangeRecords(nonFunction); }, TypeError
); | 146 assertThrows(function() { Object.deliverChangeRecords(nonFunction); }, TypeError
); |
| 144 | 147 |
| 145 Object.observe(obj, observer.callback); | 148 Object.observe(obj, observer.callback); |
| 146 | 149 |
| 150 |
| 147 // notify uses to [[CreateOwnProperty]] to create changeRecord; | 151 // notify uses to [[CreateOwnProperty]] to create changeRecord; |
| 148 reset(); | 152 reset(); |
| 149 var protoExpandoAccessed = false; | 153 var protoExpandoAccessed = false; |
| 150 Object.defineProperty(Object.prototype, 'protoExpando', | 154 Object.defineProperty(Object.prototype, 'protoExpando', |
| 151 { | 155 { |
| 152 configurable: true, | 156 configurable: true, |
| 153 set: function() { protoExpandoAccessed = true; } | 157 set: function() { protoExpandoAccessed = true; } |
| 154 } | 158 } |
| 155 ); | 159 ); |
| 156 notifier.notify({ type: 'foo', protoExpando: 'val'}); | 160 notifier.notify({ type: 'foo', protoExpando: 'val'}); |
| 157 assertFalse(protoExpandoAccessed); | 161 assertFalse(protoExpandoAccessed); |
| 158 delete Object.prototype.protoExpando; | 162 delete Object.prototype.protoExpando; |
| 159 Object.deliverChangeRecords(observer.callback); | 163 Object.deliverChangeRecords(observer.callback); |
| 160 | 164 |
| 165 |
| 161 // Multiple records are delivered. | 166 // Multiple records are delivered. |
| 162 reset(); | 167 reset(); |
| 163 notifier.notify({ | 168 notifier.notify({ |
| 164 type: 'updated', | 169 type: 'updated', |
| 165 name: 'foo', | 170 name: 'foo', |
| 166 expando: 1 | 171 expando: 1 |
| 167 }); | 172 }); |
| 168 | 173 |
| 169 notifier.notify({ | 174 notifier.notify({ |
| 170 object: notifier, // object property is ignored | 175 object: notifier, // object property is ignored |
| 171 type: 'deleted', | 176 type: 'deleted', |
| 172 name: 'bar', | 177 name: 'bar', |
| 173 expando2: 'str' | 178 expando2: 'str' |
| 174 }); | 179 }); |
| 175 Object.deliverChangeRecords(observer.callback); | 180 Object.deliverChangeRecords(observer.callback); |
| 176 observer.assertCallbackRecords([ | 181 observer.assertCallbackRecords([ |
| 177 { object: obj, name: 'foo', type: 'updated', expando: 1 }, | 182 { object: obj, name: 'foo', type: 'updated', expando: 1 }, |
| 178 { object: obj, name: 'bar', type: 'deleted', expando2: 'str' } | 183 { object: obj, name: 'bar', type: 'deleted', expando2: 'str' } |
| 179 ]); | 184 ]); |
| 180 | 185 |
| 186 |
| 181 // No delivery takes place if no records are pending | 187 // No delivery takes place if no records are pending |
| 182 reset(); | 188 reset(); |
| 183 Object.deliverChangeRecords(observer.callback); | 189 Object.deliverChangeRecords(observer.callback); |
| 184 observer.assertNotCalled(); | 190 observer.assertNotCalled(); |
| 185 | 191 |
| 192 |
| 186 // Multiple observation has no effect. | 193 // Multiple observation has no effect. |
| 187 reset(); | 194 reset(); |
| 188 Object.observe(obj, observer.callback); | 195 Object.observe(obj, observer.callback); |
| 189 Object.observe(obj, observer.callback); | 196 Object.observe(obj, observer.callback); |
| 190 Object.getNotifier(obj).notify({ | 197 Object.getNotifier(obj).notify({ |
| 191 type: 'foo', | 198 type: 'foo', |
| 192 }); | 199 }); |
| 193 Object.deliverChangeRecords(observer.callback); | 200 Object.deliverChangeRecords(observer.callback); |
| 194 observer.assertCalled(); | 201 observer.assertCalled(); |
| 195 | 202 |
| 203 |
| 196 // Observation can be stopped. | 204 // Observation can be stopped. |
| 197 reset(); | 205 reset(); |
| 198 Object.unobserve(obj, observer.callback); | 206 Object.unobserve(obj, observer.callback); |
| 199 Object.getNotifier(obj).notify({ | 207 Object.getNotifier(obj).notify({ |
| 200 type: 'foo', | 208 type: 'foo', |
| 201 }); | 209 }); |
| 202 Object.deliverChangeRecords(observer.callback); | 210 Object.deliverChangeRecords(observer.callback); |
| 203 observer.assertNotCalled(); | 211 observer.assertNotCalled(); |
| 204 | 212 |
| 213 |
| 205 // Multiple unobservation has no effect | 214 // Multiple unobservation has no effect |
| 206 reset(); | 215 reset(); |
| 207 Object.unobserve(obj, observer.callback); | 216 Object.unobserve(obj, observer.callback); |
| 208 Object.unobserve(obj, observer.callback); | 217 Object.unobserve(obj, observer.callback); |
| 209 Object.getNotifier(obj).notify({ | 218 Object.getNotifier(obj).notify({ |
| 210 type: 'foo', | 219 type: 'foo', |
| 211 }); | 220 }); |
| 212 Object.deliverChangeRecords(observer.callback); | 221 Object.deliverChangeRecords(observer.callback); |
| 213 observer.assertNotCalled(); | 222 observer.assertNotCalled(); |
| 214 | 223 |
| 224 |
| 215 // Re-observation works and only includes changeRecords after of call. | 225 // Re-observation works and only includes changeRecords after of call. |
| 216 reset(); | 226 reset(); |
| 217 Object.getNotifier(obj).notify({ | 227 Object.getNotifier(obj).notify({ |
| 218 type: 'foo', | 228 type: 'foo', |
| 219 }); | 229 }); |
| 220 Object.observe(obj, observer.callback); | 230 Object.observe(obj, observer.callback); |
| 221 Object.getNotifier(obj).notify({ | 231 Object.getNotifier(obj).notify({ |
| 222 type: 'foo', | 232 type: 'foo', |
| 223 }); | 233 }); |
| 224 records = undefined; | 234 records = undefined; |
| 225 Object.deliverChangeRecords(observer.callback); | 235 Object.deliverChangeRecords(observer.callback); |
| 226 observer.assertRecordCount(1); | 236 observer.assertRecordCount(1); |
| 227 | 237 |
| 238 |
| 228 // Observing a continuous stream of changes, while itermittantly unobserving. | 239 // Observing a continuous stream of changes, while itermittantly unobserving. |
| 229 reset(); | 240 reset(); |
| 230 Object.observe(obj, observer.callback); | 241 Object.observe(obj, observer.callback); |
| 231 Object.getNotifier(obj).notify({ | 242 Object.getNotifier(obj).notify({ |
| 232 type: 'foo', | 243 type: 'foo', |
| 233 val: 1 | 244 val: 1 |
| 234 }); | 245 }); |
| 235 | 246 |
| 236 Object.unobserve(obj, observer.callback); | 247 Object.unobserve(obj, observer.callback); |
| 237 Object.getNotifier(obj).notify({ | 248 Object.getNotifier(obj).notify({ |
| (...skipping 20 matching lines...) Expand all Loading... |
| 258 }); | 269 }); |
| 259 | 270 |
| 260 Object.unobserve(obj, observer.callback); | 271 Object.unobserve(obj, observer.callback); |
| 261 Object.deliverChangeRecords(observer.callback); | 272 Object.deliverChangeRecords(observer.callback); |
| 262 observer.assertCallbackRecords([ | 273 observer.assertCallbackRecords([ |
| 263 { object: obj, type: 'foo', val: 1 }, | 274 { object: obj, type: 'foo', val: 1 }, |
| 264 { object: obj, type: 'foo', val: 3 }, | 275 { object: obj, type: 'foo', val: 3 }, |
| 265 { object: obj, type: 'foo', val: 5 } | 276 { object: obj, type: 'foo', val: 5 } |
| 266 ]); | 277 ]); |
| 267 | 278 |
| 279 |
| 268 // Observing multiple objects; records appear in order. | 280 // Observing multiple objects; records appear in order. |
| 269 reset(); | 281 reset(); |
| 270 var obj2 = {}; | 282 var obj2 = {}; |
| 271 var obj3 = {} | 283 var obj3 = {} |
| 272 Object.observe(obj, observer.callback); | 284 Object.observe(obj, observer.callback); |
| 273 Object.observe(obj3, observer.callback); | 285 Object.observe(obj3, observer.callback); |
| 274 Object.observe(obj2, observer.callback); | 286 Object.observe(obj2, observer.callback); |
| 275 Object.getNotifier(obj).notify({ | 287 Object.getNotifier(obj).notify({ |
| 276 type: 'foo1', | 288 type: 'foo1', |
| 277 }); | 289 }); |
| 278 Object.getNotifier(obj2).notify({ | 290 Object.getNotifier(obj2).notify({ |
| 279 type: 'foo2', | 291 type: 'foo2', |
| 280 }); | 292 }); |
| 281 Object.getNotifier(obj3).notify({ | 293 Object.getNotifier(obj3).notify({ |
| 282 type: 'foo3', | 294 type: 'foo3', |
| 283 }); | 295 }); |
| 284 Object.observe(obj3, observer.callback); | 296 Object.observe(obj3, observer.callback); |
| 285 Object.deliverChangeRecords(observer.callback); | 297 Object.deliverChangeRecords(observer.callback); |
| 286 observer.assertCallbackRecords([ | 298 observer.assertCallbackRecords([ |
| 287 { object: obj, type: 'foo1' }, | 299 { object: obj, type: 'foo1' }, |
| 288 { object: obj2, type: 'foo2' }, | 300 { object: obj2, type: 'foo2' }, |
| 289 { object: obj3, type: 'foo3' } | 301 { object: obj3, type: 'foo3' } |
| 290 ]); | 302 ]); |
| 291 | 303 |
| 304 |
| 305 // Recursive observation. |
| 306 var obj = {a: 1}; |
| 307 var callbackCount = 0; |
| 308 function recursiveObserver(r) { |
| 309 assertEquals(1, r.length); |
| 310 ++callbackCount; |
| 311 if (r[0].oldValue < 100) ++obj[r[0].name]; |
| 312 } |
| 313 Object.observe(obj, recursiveObserver); |
| 314 ++obj.a; |
| 315 Object.deliverChangeRecords(recursiveObserver); |
| 316 assertEquals(100, callbackCount); |
| 317 |
| 318 var obj1 = {a: 1}; |
| 319 var obj2 = {a: 1}; |
| 320 var recordCount = 0; |
| 321 function recursiveObserver2(r) { |
| 322 recordCount += r.length; |
| 323 if (r[0].oldValue < 100) { |
| 324 ++obj1.a; |
| 325 ++obj2.a; |
| 326 } |
| 327 } |
| 328 Object.observe(obj1, recursiveObserver2); |
| 329 Object.observe(obj2, recursiveObserver2); |
| 330 ++obj1.a; |
| 331 Object.deliverChangeRecords(recursiveObserver2); |
| 332 assertEquals(199, recordCount); |
| 333 |
| 334 |
| 292 // Observing named properties. | 335 // Observing named properties. |
| 293 reset(); | 336 reset(); |
| 294 var obj = {a: 1} | 337 var obj = {a: 1} |
| 295 Object.observe(obj, observer.callback); | 338 Object.observe(obj, observer.callback); |
| 296 obj.a = 2; | 339 obj.a = 2; |
| 297 obj["a"] = 3; | 340 obj["a"] = 3; |
| 298 delete obj.a; | 341 delete obj.a; |
| 299 obj.a = 4; | 342 obj.a = 4; |
| 300 obj.a = 4; // ignored | 343 obj.a = 4; // ignored |
| 301 obj.a = 5; | 344 obj.a = 5; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 { object: obj, name: "a", type: "reconfigured" }, | 376 { object: obj, name: "a", type: "reconfigured" }, |
| 334 { object: obj, name: "a", type: "reconfigured" }, | 377 { object: obj, name: "a", type: "reconfigured" }, |
| 335 { object: obj, name: "a", type: "deleted" }, | 378 { object: obj, name: "a", type: "deleted" }, |
| 336 { object: obj, name: "a", type: "new" }, | 379 { object: obj, name: "a", type: "new" }, |
| 337 { object: obj, name: "a", type: "reconfigured" }, | 380 { object: obj, name: "a", type: "reconfigured" }, |
| 338 { object: obj, name: "a", type: "updated", oldValue: 9 }, | 381 { object: obj, name: "a", type: "updated", oldValue: 9 }, |
| 339 { object: obj, name: "a", type: "deleted", oldValue: 10 }, | 382 { object: obj, name: "a", type: "deleted", oldValue: 10 }, |
| 340 { object: obj, name: "a", type: "new" }, | 383 { object: obj, name: "a", type: "new" }, |
| 341 ]); | 384 ]); |
| 342 | 385 |
| 386 |
| 343 // Observing indexed properties. | 387 // Observing indexed properties. |
| 344 reset(); | 388 reset(); |
| 345 var obj = {'1': 1} | 389 var obj = {'1': 1} |
| 346 Object.observe(obj, observer.callback); | 390 Object.observe(obj, observer.callback); |
| 347 obj[1] = 2; | 391 obj[1] = 2; |
| 348 obj[1] = 3; | 392 obj[1] = 3; |
| 349 delete obj[1]; | 393 delete obj[1]; |
| 350 obj[1] = 4; | 394 obj[1] = 4; |
| 351 obj[1] = 4; // ignored | 395 obj[1] = 4; // ignored |
| 352 obj[1] = 5; | 396 obj[1] = 5; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 function TestObserveNonConfigurable(obj, prop, desc) { | 503 function TestObserveNonConfigurable(obj, prop, desc) { |
| 460 reset(); | 504 reset(); |
| 461 obj[prop] = 1; | 505 obj[prop] = 1; |
| 462 Object.observe(obj, observer.callback); | 506 Object.observe(obj, observer.callback); |
| 463 obj[prop] = 4; | 507 obj[prop] = 4; |
| 464 obj[prop] = 4; // ignored | 508 obj[prop] = 4; // ignored |
| 465 obj[prop] = 5; | 509 obj[prop] = 5; |
| 466 Object.defineProperty(obj, prop, {value: 6}); | 510 Object.defineProperty(obj, prop, {value: 6}); |
| 467 Object.defineProperty(obj, prop, {value: 6}); // ignored | 511 Object.defineProperty(obj, prop, {value: 6}); // ignored |
| 468 Object.defineProperty(obj, prop, {value: 7}); | 512 Object.defineProperty(obj, prop, {value: 7}); |
| 469 Object.defineProperty(obj, prop, | 513 Object.defineProperty(obj, prop, {enumerable: desc.enumerable}); // ignored |
| 470 {enumerable: desc.enumerable}); // ignored | |
| 471 Object.defineProperty(obj, prop, {writable: false}); | 514 Object.defineProperty(obj, prop, {writable: false}); |
| 472 obj[prop] = 7; // ignored | 515 obj[prop] = 7; // ignored |
| 473 Object.deliverChangeRecords(observer.callback); | 516 Object.deliverChangeRecords(observer.callback); |
| 474 observer.assertCallbackRecords([ | 517 observer.assertCallbackRecords([ |
| 475 { object: obj, name: prop, type: "updated", oldValue: 1 }, | 518 { object: obj, name: prop, type: "updated", oldValue: 1 }, |
| 476 { object: obj, name: prop, type: "updated", oldValue: 4 }, | 519 { object: obj, name: prop, type: "updated", oldValue: 4 }, |
| 477 { object: obj, name: prop, type: "updated", oldValue: 5 }, | 520 { object: obj, name: prop, type: "updated", oldValue: 5 }, |
| 478 { object: obj, name: prop, type: "updated", oldValue: 6 }, | 521 { object: obj, name: prop, type: "updated", oldValue: 6 }, |
| 479 { object: obj, name: prop, type: "reconfigured", oldValue: 7 }, | 522 { object: obj, name: prop, type: "reconfigured", oldValue: 7 }, |
| 480 ]); | 523 ]); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 new Set, new Map, new WeakMap, | 577 new Set, new Map, new WeakMap, |
| 535 new ArrayBuffer(10), new Int32Array(5), | 578 new ArrayBuffer(10), new Int32Array(5), |
| 536 createProxy(Proxy.create, null), | 579 createProxy(Proxy.create, null), |
| 537 createProxy(Proxy.createFunction, function(){}), | 580 createProxy(Proxy.createFunction, function(){}), |
| 538 ]; | 581 ]; |
| 539 var properties = ["a", "1", 1, "length", "prototype", "name", "caller"]; | 582 var properties = ["a", "1", 1, "length", "prototype", "name", "caller"]; |
| 540 | 583 |
| 541 // Cases that yield non-standard results. | 584 // Cases that yield non-standard results. |
| 542 function blacklisted(obj, prop) { | 585 function blacklisted(obj, prop) { |
| 543 return (obj instanceof Int32Array && prop == 1) || | 586 return (obj instanceof Int32Array && prop == 1) || |
| 544 (obj instanceof Int32Array && prop === "length") || | 587 (obj instanceof Int32Array && prop === "length") || |
| 545 (obj instanceof ArrayBuffer && prop == 1) | 588 (obj instanceof ArrayBuffer && prop == 1) |
| 546 } | 589 } |
| 547 | 590 |
| 548 for (var i in objects) for (var j in properties) { | 591 for (var i in objects) for (var j in properties) { |
| 549 var obj = objects[i]; | 592 var obj = objects[i]; |
| 550 var prop = properties[j]; | 593 var prop = properties[j]; |
| 551 if (blacklisted(obj, prop)) continue; | 594 if (blacklisted(obj, prop)) continue; |
| 552 var desc = Object.getOwnPropertyDescriptor(obj, prop); | 595 var desc = Object.getOwnPropertyDescriptor(obj, prop); |
| 553 print("***", typeof obj, stringifyNoThrow(obj), prop); | 596 print("***", typeof obj, stringifyNoThrow(obj), prop); |
| 554 if (!desc || desc.configurable) | 597 if (!desc || desc.configurable) |
| 555 TestObserveConfigurable(obj, prop); | 598 TestObserveConfigurable(obj, prop); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 { object: arr2, name: '1', type: 'deleted', oldValue: 'beta' }, | 640 { object: arr2, name: '1', type: 'deleted', oldValue: 'beta' }, |
| 598 { object: arr2, name: 'length', type: 'updated', oldValue: 2 }, | 641 { object: arr2, name: 'length', type: 'updated', oldValue: 2 }, |
| 599 { object: arr2, name: 'length', type: 'reconfigured', oldValue: 1 }, | 642 { object: arr2, name: 'length', type: 'reconfigured', oldValue: 1 }, |
| 600 { object: arr3, name: '2', type: 'deleted', oldValue: 'goodbye' }, | 643 { object: arr3, name: '2', type: 'deleted', oldValue: 'goodbye' }, |
| 601 { object: arr3, name: '0', type: 'deleted', oldValue: 'hello' }, | 644 { object: arr3, name: '0', type: 'deleted', oldValue: 'hello' }, |
| 602 { object: arr3, name: 'length', type: 'updated', oldValue: 6 }, | 645 { object: arr3, name: 'length', type: 'updated', oldValue: 6 }, |
| 603 { object: arr3, name: 'length', type: 'updated', oldValue: 0 }, | 646 { object: arr3, name: 'length', type: 'updated', oldValue: 0 }, |
| 604 { object: arr3, name: 'length', type: 'reconfigured', oldValue: 5 }, | 647 { object: arr3, name: 'length', type: 'reconfigured', oldValue: 5 }, |
| 605 ]); | 648 ]); |
| 606 | 649 |
| 650 |
| 607 // Assignments in loops (checking different IC states). | 651 // Assignments in loops (checking different IC states). |
| 608 reset(); | 652 reset(); |
| 609 var obj = {}; | 653 var obj = {}; |
| 610 Object.observe(obj, observer.callback); | 654 Object.observe(obj, observer.callback); |
| 611 for (var i = 0; i < 5; i++) { | 655 for (var i = 0; i < 5; i++) { |
| 612 obj["a" + i] = i; | 656 obj["a" + i] = i; |
| 613 } | 657 } |
| 614 Object.deliverChangeRecords(observer.callback); | 658 Object.deliverChangeRecords(observer.callback); |
| 615 observer.assertCallbackRecords([ | 659 observer.assertCallbackRecords([ |
| 616 { object: obj, name: "a0", type: "new" }, | 660 { object: obj, name: "a0", type: "new" }, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 628 } | 672 } |
| 629 Object.deliverChangeRecords(observer.callback); | 673 Object.deliverChangeRecords(observer.callback); |
| 630 observer.assertCallbackRecords([ | 674 observer.assertCallbackRecords([ |
| 631 { object: obj, name: "0", type: "new" }, | 675 { object: obj, name: "0", type: "new" }, |
| 632 { object: obj, name: "1", type: "new" }, | 676 { object: obj, name: "1", type: "new" }, |
| 633 { object: obj, name: "2", type: "new" }, | 677 { object: obj, name: "2", type: "new" }, |
| 634 { object: obj, name: "3", type: "new" }, | 678 { object: obj, name: "3", type: "new" }, |
| 635 { object: obj, name: "4", type: "new" }, | 679 { object: obj, name: "4", type: "new" }, |
| 636 ]); | 680 ]); |
| 637 | 681 |
| 682 |
| 638 // Adding elements past the end of an array should notify on length | 683 // Adding elements past the end of an array should notify on length |
| 639 reset(); | 684 reset(); |
| 640 var arr = [1, 2, 3]; | 685 var arr = [1, 2, 3]; |
| 641 Object.observe(arr, observer.callback); | 686 Object.observe(arr, observer.callback); |
| 642 arr[3] = 10; | 687 arr[3] = 10; |
| 643 arr[100] = 20; | 688 arr[100] = 20; |
| 644 Object.defineProperty(arr, '200', {value: 7}); | 689 Object.defineProperty(arr, '200', {value: 7}); |
| 645 Object.defineProperty(arr, '400', {get: function(){}}); | 690 Object.defineProperty(arr, '400', {get: function(){}}); |
| 646 arr[50] = 30; // no length change expected | 691 arr[50] = 30; // no length change expected |
| 647 Object.deliverChangeRecords(observer.callback); | 692 Object.deliverChangeRecords(observer.callback); |
| 648 observer.assertCallbackRecords([ | 693 observer.assertCallbackRecords([ |
| 649 { object: arr, name: '3', type: 'new' }, | 694 { object: arr, name: '3', type: 'new' }, |
| 650 { object: arr, name: 'length', type: 'updated', oldValue: 3 }, | 695 { object: arr, name: 'length', type: 'updated', oldValue: 3 }, |
| 651 { object: arr, name: '100', type: 'new' }, | 696 { object: arr, name: '100', type: 'new' }, |
| 652 { object: arr, name: 'length', type: 'updated', oldValue: 4 }, | 697 { object: arr, name: 'length', type: 'updated', oldValue: 4 }, |
| 653 { object: arr, name: '200', type: 'new' }, | 698 { object: arr, name: '200', type: 'new' }, |
| 654 { object: arr, name: 'length', type: 'updated', oldValue: 101 }, | 699 { object: arr, name: 'length', type: 'updated', oldValue: 101 }, |
| 655 { object: arr, name: '400', type: 'new' }, | 700 { object: arr, name: '400', type: 'new' }, |
| 656 { object: arr, name: 'length', type: 'updated', oldValue: 201 }, | 701 { object: arr, name: 'length', type: 'updated', oldValue: 201 }, |
| 657 { object: arr, name: '50', type: 'new' }, | 702 { object: arr, name: '50', type: 'new' }, |
| 658 ]); | 703 ]); |
| 659 | 704 |
| 705 |
| 660 // Tests for array methods, first on arrays and then on plain objects | 706 // Tests for array methods, first on arrays and then on plain objects |
| 661 // | 707 // |
| 662 // === ARRAYS === | 708 // === ARRAYS === |
| 663 // | 709 // |
| 664 // Push | 710 // Push |
| 665 reset(); | 711 reset(); |
| 666 var array = [1, 2]; | 712 var array = [1, 2]; |
| 667 Object.observe(array, observer.callback); | 713 Object.observe(array, observer.callback); |
| 668 array.push(3, 4); | 714 array.push(3, 4); |
| 669 Object.deliverChangeRecords(observer.callback); | 715 Object.deliverChangeRecords(observer.callback); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 Object.observe(array, observer.callback); | 769 Object.observe(array, observer.callback); |
| 724 array.splice(1, 1, 4, 5); | 770 array.splice(1, 1, 4, 5); |
| 725 Object.deliverChangeRecords(observer.callback); | 771 Object.deliverChangeRecords(observer.callback); |
| 726 observer.assertCallbackRecords([ | 772 observer.assertCallbackRecords([ |
| 727 { object: array, name: '3', type: 'new' }, | 773 { object: array, name: '3', type: 'new' }, |
| 728 { object: array, name: 'length', type: 'updated', oldValue: 3 }, | 774 { object: array, name: 'length', type: 'updated', oldValue: 3 }, |
| 729 { object: array, name: '1', type: 'updated', oldValue: 2 }, | 775 { object: array, name: '1', type: 'updated', oldValue: 2 }, |
| 730 { object: array, name: '2', type: 'updated', oldValue: 3 }, | 776 { object: array, name: '2', type: 'updated', oldValue: 3 }, |
| 731 ]); | 777 ]); |
| 732 | 778 |
| 779 |
| 733 // | 780 // |
| 734 // === PLAIN OBJECTS === | 781 // === PLAIN OBJECTS === |
| 735 // | 782 // |
| 736 // Push | 783 // Push |
| 737 reset() | 784 reset() |
| 738 var array = {0: 1, 1: 2, length: 2} | 785 var array = {0: 1, 1: 2, length: 2} |
| 739 Object.observe(array, observer.callback); | 786 Object.observe(array, observer.callback); |
| 740 Array.prototype.push.call(array, 3, 4); | 787 Array.prototype.push.call(array, 3, 4); |
| 741 Object.deliverChangeRecords(observer.callback); | 788 Object.deliverChangeRecords(observer.callback); |
| 742 observer.assertCallbackRecords([ | 789 observer.assertCallbackRecords([ |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 // TODO(adamk): Add tests for objects with hidden prototypes | 876 // TODO(adamk): Add tests for objects with hidden prototypes |
| 830 // once we support observing the global object. | 877 // once we support observing the global object. |
| 831 Object.deliverChangeRecords(observer.callback); | 878 Object.deliverChangeRecords(observer.callback); |
| 832 observer.assertCallbackRecords([ | 879 observer.assertCallbackRecords([ |
| 833 { object: obj, name: '__proto__', type: 'prototype', | 880 { object: obj, name: '__proto__', type: 'prototype', |
| 834 oldValue: Object.prototype }, | 881 oldValue: Object.prototype }, |
| 835 { object: obj, name: '__proto__', type: 'prototype', oldValue: p }, | 882 { object: obj, name: '__proto__', type: 'prototype', oldValue: p }, |
| 836 { object: obj, name: '__proto__', type: 'prototype', oldValue: null }, | 883 { object: obj, name: '__proto__', type: 'prototype', oldValue: null }, |
| 837 ]); | 884 ]); |
| 838 | 885 |
| 886 |
| 839 // Function.prototype | 887 // Function.prototype |
| 840 reset(); | 888 reset(); |
| 841 var fun = function(){}; | 889 var fun = function(){}; |
| 842 Object.observe(fun, observer.callback); | 890 Object.observe(fun, observer.callback); |
| 843 var myproto = {foo: 'bar'}; | 891 var myproto = {foo: 'bar'}; |
| 844 fun.prototype = myproto; | 892 fun.prototype = myproto; |
| 845 fun.prototype = 7; | 893 fun.prototype = 7; |
| 846 fun.prototype = 7; // ignored | 894 fun.prototype = 7; // ignored |
| 847 Object.defineProperty(fun, 'prototype', {value: 8}); | 895 Object.defineProperty(fun, 'prototype', {value: 8}); |
| 848 Object.deliverChangeRecords(observer.callback); | 896 Object.deliverChangeRecords(observer.callback); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 897 observer.assertCallbackRecords([ | 945 observer.assertCallbackRecords([ |
| 898 { object: arr, name: '1', type: 'updated', oldValue: 212 } | 946 { object: arr, name: '1', type: 'updated', oldValue: 212 } |
| 899 ]); | 947 ]); |
| 900 } | 948 } |
| 901 | 949 |
| 902 for (var b1 = 0; b1 < 2; ++b1) | 950 for (var b1 = 0; b1 < 2; ++b1) |
| 903 for (var b2 = 0; b2 < 2; ++b2) | 951 for (var b2 = 0; b2 < 2; ++b2) |
| 904 for (var b3 = 0; b3 < 2; ++b3) | 952 for (var b3 = 0; b3 < 2; ++b3) |
| 905 TestFastElements(b1 != 0, b2 != 0, b3 != 0); | 953 TestFastElements(b1 != 0, b2 != 0, b3 != 0); |
| 906 | 954 |
| 907 | |
| 908 function TestFastElementsLength(polymorphic, optimize, oldSize, newSize) { | 955 function TestFastElementsLength(polymorphic, optimize, oldSize, newSize) { |
| 909 var setLength = eval( | 956 var setLength = eval( |
| 910 "(function setLength(a, n) { a.length = n " + | 957 "(function setLength(a, n) { a.length = n " + |
| 911 "/* " + polymorphic + " " + optimize + " " + oldSize + " " + newSize + " */" | 958 "/* " + polymorphic + " " + optimize + " " + oldSize + " " + newSize + " */" |
| 912 + "})" | 959 + "})" |
| 913 ); | 960 ); |
| 914 print("TestFastElementsLength:", setLength); | 961 print("TestFastElementsLength:", setLength); |
| 915 | 962 |
| 916 function array(n) { | 963 function array(n) { |
| 917 var arr = new Array(n); | 964 var arr = new Array(n); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 941 assertEquals('updated', lengthRecord.type); | 988 assertEquals('updated', lengthRecord.type); |
| 942 assertSame(oldSize, lengthRecord.oldValue); | 989 assertSame(oldSize, lengthRecord.oldValue); |
| 943 } | 990 } |
| 944 } | 991 } |
| 945 | 992 |
| 946 for (var b1 = 0; b1 < 2; ++b1) | 993 for (var b1 = 0; b1 < 2; ++b1) |
| 947 for (var b2 = 0; b2 < 2; ++b2) | 994 for (var b2 = 0; b2 < 2; ++b2) |
| 948 for (var n1 = 0; n1 < 3; ++n1) | 995 for (var n1 = 0; n1 < 3; ++n1) |
| 949 for (var n2 = 0; n2 < 3; ++n2) | 996 for (var n2 = 0; n2 < 3; ++n2) |
| 950 TestFastElementsLength(b1 != 0, b2 != 0, 20*n1, 20*n2); | 997 TestFastElementsLength(b1 != 0, b2 != 0, 20*n1, 20*n2); |
| OLD | NEW |