js/src/tests/js1_8_5/extensions/clone-complex-object.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial