OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2012 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 // Flags: --harmony-object-observe | |
29 | |
30 var records; | |
31 var callbackCount; | |
32 function reset() { | |
33 records = undefined; | |
34 callbackCount = 0; | |
35 } | |
36 reset(); | |
37 function assertNoCallback() { | |
38 assertEquals(undefined, records); | |
39 assertEquals(0, callbackCount); | |
40 } | |
41 | |
42 var obj = {}; | |
43 function obs(r) { | |
44 callbackCount++; | |
45 records = r; | |
46 } | |
47 | |
48 function frozenFunction() {} | |
49 Object.freeze(frozenFunction); | |
50 var nonFunction = {}; | |
51 var changeRecordWithAccessor = { type: 'foo' }; | |
52 var recordCreated = false; | |
53 Object.defineProperty(changeRecordWithAccessor, 'name', { | |
54 get: function() { | |
55 recordCreated = true; | |
56 }, | |
57 enumerable: true | |
58 }) | |
59 | |
60 // Object.observe | |
61 assertThrows(function() { Object.observe("non-object", obs); }, TypeError); | |
62 assertThrows(function() { Object.observe(obj, nonFunction); }, TypeError); | |
63 assertThrows(function() { Object.observe(obj, frozenFunction); }, TypeError); | |
64 | |
65 // Object.unobserve | |
66 assertThrows(function() { Object.unobserve(4, obs); }, TypeError); | |
67 | |
68 // Object.notify | |
69 assertThrows(function() { Object.notify(obs, {}); }, TypeError); | |
70 assertThrows(function() { Object.notify(obs, { type: 4 }); }, TypeError); | |
71 Object.notify(obs, changeRecordWithAccessor); | |
72 assertFalse(recordCreated); | |
73 | |
74 // Object.deliverChangeRecords | |
75 assertThrows(function() { Object.deliverChangeRecords(nonFunction); }, TypeError ); | |
76 | |
77 // Multiple records are delivered. | |
78 Object.observe(obj, obs); | |
79 Object.notify(obj, { | |
80 object: obj, | |
81 type: 'updated', | |
82 name: 'foo', | |
83 expando: 1 | |
84 }); | |
85 | |
86 Object.notify(obj, { | |
87 object: obj, | |
88 type: 'deleted', | |
89 name: 'bar', | |
90 expando2: 'str' | |
91 }); | |
92 Object.deliverChangeRecords(obs); | |
93 assertEquals(1, callbackCount); | |
94 assertEquals(2, records.length); | |
95 assertSame(obj, records[0].object); | |
96 assertEquals('foo', records[0].name); | |
97 assertEquals('updated', records[0].type); | |
98 assertEquals(1, records[0].expando); | |
99 assertSame(obj, records[1].object); | |
100 assertEquals('bar', records[1].name); | |
101 assertEquals('deleted', records[1].type); | |
102 assertEquals('str', records[1].expando2); | |
103 assertEquals(undefined, records[1].expando); | |
104 | |
105 // No delivery takes place if no records are pending | |
106 reset(); | |
107 Object.deliverChangeRecords(obs); | |
108 assertNoCallback(); | |
109 | |
110 // Multiple observation has no effect. | |
111 reset(); | |
112 Object.observe(obj, obs); | |
113 Object.observe(obj, obs); | |
114 Object.notify(obj, { | |
115 type: 'foo', | |
116 }); | |
117 Object.deliverChangeRecords(obs); | |
118 assertEquals(1, callbackCount); | |
119 | |
120 // Observation can be stopped. | |
121 reset(); | |
122 Object.unobserve(obj, obs); | |
123 Object.notify(obj, { | |
124 type: 'foo', | |
125 }); | |
126 Object.deliverChangeRecords(obs); | |
127 assertNoCallback(); | |
128 | |
129 // Multiple unobservation has no effect | |
130 reset(); | |
131 Object.unobserve(obj, obs); | |
132 Object.unobserve(obj, obs); | |
133 Object.notify(obj, { | |
134 type: 'foo', | |
135 }); | |
136 Object.deliverChangeRecords(obs); | |
137 assertNoCallback(); | |
138 | |
139 // Re-observation works and only includes changeRecords after of call. | |
140 reset(); | |
141 Object.notify(obj, { | |
142 type: 'foo', | |
143 }); | |
144 Object.observe(obj, obs); | |
145 Object.notify(obj, { | |
146 type: 'foo', | |
147 }); | |
148 records = undefined; | |
149 Object.deliverChangeRecords(obs); | |
150 assertEquals(1, callbackCount); | |
151 assertEquals(1, records.length); | |
152 | |
153 // Observing a continuous stream of changes, while itermittantly unobserving. | |
154 reset(); | |
155 Object.observe(obj, obs); | |
156 Object.notify(obj, { | |
157 type: 'foo', | |
158 val: 1 | |
159 }); | |
160 | |
161 Object.unobserve(obj, obs); | |
162 Object.notify(obj, { | |
163 type: 'foo', | |
164 val: 2 | |
165 }); | |
166 | |
167 Object.observe(obj, obs); | |
168 Object.notify(obj, { | |
169 type: 'foo', | |
170 val: 3 | |
171 }); | |
172 | |
173 Object.unobserve(obj, obs); | |
174 Object.notify(obj, { | |
175 type: 'foo', | |
176 val: 4 | |
177 }); | |
178 | |
179 Object.observe(obj, obs); | |
180 Object.notify(obj, { | |
181 type: 'foo', | |
182 val: 5 | |
183 }); | |
184 | |
185 Object.unobserve(obj, obs); | |
186 Object.deliverChangeRecords(obs); | |
187 assertEquals(1, callbackCount); | |
188 assertEquals(3, records.length); | |
189 assertSame(1, records[0].val); | |
190 assertSame(3, records[1].val); | |
191 assertSame(5, records[2].val); | |
192 | |
193 // Observing multiple objects; records appear in order;. | |
194 reset(); | |
195 var obj2 = {}; | |
196 var obj3 = {} | |
197 Object.observe(obj, obs); | |
198 Object.observe(obj3, obs); | |
199 Object.observe(obj2, obs); | |
rossberg
2012/10/24 12:03:13
Nit: is there a reason you observe 3 before 2?
rafaelw
2012/10/24 14:56:05
Because the naive implementation might have ordere
| |
200 Object.notify(obj, { | |
201 type: 'foo', | |
202 }); | |
203 Object.notify(obj2, { | |
204 type: 'foo', | |
205 }); | |
206 Object.notify(obj3, { | |
207 type: 'foo', | |
208 }); | |
209 Object.deliverChangeRecords(obs); | |
210 assertEquals(1, callbackCount); | |
211 assertEquals(3, records.length); | |
212 assertSame(obj, records[0].object); | |
213 assertSame(obj2, records[1].object); | |
214 assertSame(obj3, records[2].object); | |
OLD | NEW |