Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // |reftest| skip-if(!xulRuntime.shell)
2 // -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 // Any copyright is dedicated to the Public Domain.
4 // http://creativecommons.org/licenses/publicdomain/
6 // Set of properties on a cloned object that are legitimately non-enumerable,
7 // grouped by object type.
8 var non_enumerable = { 'Array': [ 'length' ],
9 'String': [ 'length' ] };
11 // Set of properties on a cloned object that are legitimately non-configurable,
12 // grouped by object type. The property name '0' stands in for any indexed
13 // property.
14 var non_configurable = { 'String': [ 0 ],
15 '(typed array)': [ 0 ] };
17 // Set of properties on a cloned object that are legitimately non-writable,
18 // grouped by object type. The property name '0' stands in for any indexed
19 // property.
20 var non_writable = { 'String': [ 0 ] };
22 function classOf(obj) {
23 var classString = Object.prototype.toString.call(obj);
24 var [ all, classname ] = classString.match(/\[object (\w+)/);
25 return classname;
26 }
28 function isIndex(p) {
29 var u = p >>> 0;
30 return ("" + u == p && u != 0xffffffff);
31 }
33 function notIndex(p) {
34 return !isIndex(p);
35 }
37 function tableContains(table, cls, prop) {
38 if (isIndex(prop))
39 prop = 0;
40 if (cls.match(/\wArray$/))
41 cls = "(typed array)";
42 var exceptionalProps = table[cls] || [];
43 return exceptionalProps.indexOf(prop) != -1;
44 }
46 function shouldBeConfigurable(cls, prop) {
47 return !tableContains(non_configurable, cls, prop);
48 }
50 function shouldBeWritable(cls, prop) {
51 return !tableContains(non_writable, cls, prop);
52 }
54 function ownProperties(obj) {
55 return Object.getOwnPropertyNames(obj).
56 map(function (p) { return [p, Object.getOwnPropertyDescriptor(obj, p)]; });
57 }
59 function isCloneable(pair) {
60 return typeof pair[0] === 'string' && pair[1].enumerable;
61 }
63 function compareProperties(a, b, stack, path) {
64 var ca = classOf(a);
66 // 'b', the original object, may have non-enumerable or XMLName properties;
67 // ignore them. 'a', the clone, should not have any non-enumerable
68 // properties (except .length, if it's an Array or String) or XMLName
69 // properties.
70 var pb = ownProperties(b).filter(isCloneable);
71 var pa = ownProperties(a);
72 for (var i = 0; i < pa.length; i++) {
73 var propname = pa[i][0];
74 assertEq(typeof propname, "string", "clone should not have E4X properties " + path);
75 if (!pa[i][1].enumerable) {
76 if (tableContains(non_enumerable, ca, propname)) {
77 // remove it so that the comparisons below will work
78 pa.splice(i, 1);
79 i--;
80 } else {
81 throw new Error("non-enumerable clone property " + uneval(pa[i][0]) + " " + path);
82 }
83 }
84 }
86 // Check that, apart from properties whose names are array indexes,
87 // the enumerable properties appear in the same order.
88 var aNames = pa.map(function (pair) { return pair[1]; }).filter(notIndex);
89 var bNames = pa.map(function (pair) { return pair[1]; }).filter(notIndex);
90 assertEq(aNames.join(","), bNames.join(","), path);
92 // Check that the lists are the same when including array indexes.
93 function byName(a, b) { a = a[0]; b = b[0]; return a < b ? -1 : a === b ? 0 : 1; }
94 pa.sort(byName);
95 pb.sort(byName);
96 assertEq(pa.length, pb.length, "should see the same number of properties " + path);
97 for (var i = 0; i < pa.length; i++) {
98 var aName = pa[i][0];
99 var bName = pb[i][0];
100 assertEq(aName, bName, path);
102 var path2 = isIndex(aName) ? path + "[" + aName + "]" : path + "." + aName;
103 var da = pa[i][1];
104 var db = pb[i][1];
105 assertEq(da.configurable, shouldBeConfigurable(ca, aName), path2);
106 assertEq(da.writable, shouldBeWritable(ca, aName), path2);
107 assertEq("value" in da, true, path2);
108 var va = da.value;
109 var vb = b[pb[i][0]];
110 stack.push([va, vb, path2]);
111 }
112 }
114 function isClone(a, b) {
115 var stack = [[a, b, 'obj']];
116 var memory = new WeakMap();
117 var rmemory = new WeakMap();
119 while (stack.length > 0) {
120 var pair = stack.pop();
121 var x = pair[0], y = pair[1], path = pair[2];
122 if (typeof x !== "object" || x === null) {
123 // x is primitive.
124 assertEq(x, y, "equal primitives");
125 } else if (x instanceof Date) {
126 assertEq(x.getTime(), y.getTime(), "equal times for cloned Dates");
127 } else if (memory.has(x)) {
128 // x is an object we have seen before in a.
129 assertEq(y, memory.get(x), "repeated object the same");
130 assertEq(rmemory.get(y), x, "repeated object's clone already seen");
131 } else {
132 // x is an object we have not seen before.
133 // Check that we have not seen y before either.
134 assertEq(rmemory.has(y), false);
136 var xcls = classOf(x);
137 var ycls = classOf(y);
138 assertEq(xcls, ycls, "same [[Class]]");
140 // clone objects should have the default prototype of the class
141 assertEq(Object.getPrototypeOf(x), this[xcls].prototype);
143 compareProperties(x, y, stack, path);
145 // Record that we have seen this pair of objects.
146 memory.set(x, y);
147 rmemory.set(y, x);
148 }
149 }
150 return true;
151 }
153 function check(val) {
154 var clone = deserialize(serialize(val));
155 assertEq(isClone(val, clone), true);
156 return clone;
157 }
159 // Various recursive objects
161 // Recursive array.
162 var a = [];
163 a[0] = a;
164 check(a);
166 // Recursive Object.
167 var b = {};
168 b.next = b;
169 check(b);
171 // Mutually recursive objects.
172 var a = [];
173 var b = {};
174 var c = {};
175 a[0] = b;
176 a[1] = b;
177 a[2] = b;
178 b.next = a;
179 check(a);
180 check(b);
182 // A date
183 check(new Date);
185 // A recursive object that is very large.
186 a = [];
187 b = a;
188 for (var i = 0; i < 10000; i++) {
189 b[0] = {};
190 b[1] = [];
191 b = b[1];
192 }
193 b[0] = {owner: a};
194 b[1] = [];
195 check(a);
197 // Date objects should not be identical even if representing the same date
198 var ar = [ new Date(1000), new Date(1000) ];
199 var clone = check(ar);
200 assertEq(clone[0] === clone[1], false);
202 // Identity preservation for various types of objects
204 function checkSimpleIdentity(v)
205 {
206 a = check([ v, v ]);
207 assertEq(a[0] === a[1], true);
208 return a;
209 }
211 var v = new Boolean(true);
212 checkSimpleIdentity(v);
214 v = new Number(17);
215 checkSimpleIdentity(v);
217 v = new String("yo");
218 checkSimpleIdentity(v);
220 v = "fish";
221 checkSimpleIdentity(v);
223 v = new Int8Array([ 10, 20 ]);
224 checkSimpleIdentity(v);
226 v = new ArrayBuffer(7);
227 checkSimpleIdentity(v);
229 v = new Date(1000);
230 b = [ v, v, { 'date': v } ];
231 clone = check(b);
232 assertEq(clone[0] === clone[1], true);
233 assertEq(clone[0], clone[2]['date']);
234 assertEq(clone[0] === v, false);
236 // Reduced and modified from postMessage_structured_clone test
237 let foo = { };
238 let baz = { };
239 let obj = { 'foo': foo,
240 'bar': { 'foo': foo },
241 'expando': { 'expando': baz },
242 'baz': baz };
243 check(obj);
245 for (var obj of new getTestContent)
246 check(obj);
248 // Stolen wholesale from postMessage_structured_clone_helper.js
249 function getTestContent()
250 {
251 yield "hello";
252 yield 2+3;
253 yield 12;
254 yield null;
255 yield "complex" + "string";
256 yield new Object();
257 yield new Date(1306113544);
258 yield [1, 2, 3, 4, 5];
259 let obj = new Object();
260 obj.foo = 3;
261 obj.bar = "hi";
262 obj.baz = new Date(1306113544);
263 obj.boo = obj;
264 yield obj;
266 let recursiveobj = new Object();
267 recursiveobj.a = recursiveobj;
268 recursiveobj.foo = new Object();
269 recursiveobj.foo.bar = "bar";
270 recursiveobj.foo.backref = recursiveobj;
271 recursiveobj.foo.baz = 84;
272 recursiveobj.foo.backref2 = recursiveobj;
273 recursiveobj.bar = new Object();
274 recursiveobj.bar.foo = "foo";
275 recursiveobj.bar.backref = recursiveobj;
276 recursiveobj.bar.baz = new Date(1306113544);
277 recursiveobj.bar.backref2 = recursiveobj;
278 recursiveobj.expando = recursiveobj;
279 yield recursiveobj;
281 let obj = new Object();
282 obj.expando1 = 1;
283 obj.foo = new Object();
284 obj.foo.bar = 2;
285 obj.bar = new Object();
286 obj.bar.foo = obj.foo;
287 obj.expando = new Object();
288 obj.expando.expando = new Object();
289 obj.expando.expando.obj = obj;
290 obj.expando2 = 4;
291 obj.baz = obj.expando.expando;
292 obj.blah = obj.bar;
293 obj.foo.baz = obj.blah;
294 obj.foo.blah = obj.blah;
295 yield obj;
297 let diamond = new Object();
298 let obj = new Object();
299 obj.foo = "foo";
300 obj.bar = 92;
301 obj.backref = diamond;
302 diamond.ref1 = obj;
303 diamond.ref2 = obj;
304 yield diamond;
306 let doubleref = new Object();
307 let obj = new Object();
308 doubleref.ref1 = obj;
309 doubleref.ref2 = obj;
310 yield doubleref;
311 }
313 reportCompare(0, 0, 'ok');