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.

     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');

mercurial