Home | History | Annotate | Download | only in es6
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 var global = this;
      6 var globalProto = Object.getPrototypeOf(global);
      7 
      8 // Number of objects being tested. There is an assert ensuring this is correct.
      9 var objectCount = 21;
     10 
     11 
     12 function runTest(f) {
     13   function restore(object, oldProto) {
     14     delete object[Symbol.unscopables];
     15     delete object.x;
     16     delete object.x_;
     17     delete object.y;
     18     delete object.z;
     19     Object.setPrototypeOf(object, oldProto);
     20   }
     21 
     22   function getObject(i) {
     23     var objects = [
     24       {},
     25       [],
     26       function() {},
     27       function() {
     28         return arguments;
     29       }(),
     30       function() {
     31         'use strict';
     32         return arguments;
     33       }(),
     34       Object(1),
     35       Object(true),
     36       Object('bla'),
     37       new Date,
     38       new RegExp,
     39       new Set,
     40       new Map,
     41       new WeakMap,
     42       new WeakSet,
     43       new ArrayBuffer(10),
     44       new Int32Array(5),
     45       Object,
     46       Function,
     47       Date,
     48       RegExp,
     49       global
     50     ];
     51 
     52     assertEquals(objectCount, objects.length);
     53     return objects[i];
     54   }
     55 
     56   // Tests depends on this not being there to start with.
     57   delete Array.prototype[Symbol.unscopables];
     58 
     59   if (f.length === 1) {
     60     for (var i = 0; i < objectCount; i++) {
     61       var object = getObject(i);
     62       var oldObjectProto = Object.getPrototypeOf(object);
     63       f(object);
     64       restore(object, oldObjectProto);
     65     }
     66   } else {
     67     for (var i = 0; i < objectCount; i++) {
     68       for (var j = 0; j < objectCount; j++) {
     69         var object = getObject(i);
     70         var proto = getObject(j);
     71         if (object === proto) {
     72           continue;
     73         }
     74         var oldObjectProto = Object.getPrototypeOf(object);
     75         var oldProtoProto = Object.getPrototypeOf(proto);
     76         f(object, proto);
     77         restore(object, oldObjectProto);
     78         restore(proto, oldProtoProto);
     79       }
     80     }
     81   }
     82 }
     83 
     84 // Test array first, since other tests are changing
     85 // Array.prototype[Symbol.unscopables].
     86 function TestArrayPrototypeUnscopables() {
     87   var descr = Object.getOwnPropertyDescriptor(Array.prototype,
     88                                               Symbol.unscopables);
     89   assertFalse(descr.enumerable);
     90   assertFalse(descr.writable);
     91   assertTrue(descr.configurable);
     92   assertEquals(null, Object.getPrototypeOf(descr.value));
     93 
     94   var copyWithin = 'local copyWithin';
     95   var entries = 'local entries';
     96   var fill = 'local fill';
     97   var find = 'local find';
     98   var findIndex = 'local findIndex';
     99   var keys = 'local keys';
    100   var values = 'local values';
    101 
    102   var array = [];
    103   array.toString = 42;
    104 
    105   with (array) {
    106     assertEquals('local copyWithin', copyWithin);
    107     assertEquals('local entries', entries);
    108     assertEquals('local fill', fill);
    109     assertEquals('local find', find);
    110     assertEquals('local findIndex', findIndex);
    111     assertEquals('local keys', keys);
    112     assertEquals('local values', values);
    113     assertEquals(42, toString);
    114   }
    115 }
    116 TestArrayPrototypeUnscopables();
    117 
    118 
    119 
    120 function TestBasics(object) {
    121   var x = 1;
    122   var y = 2;
    123   var z = 3;
    124   object.x = 4;
    125   object.y = 5;
    126 
    127   with (object) {
    128     assertEquals(4, x);
    129     assertEquals(5, y);
    130     assertEquals(3, z);
    131   }
    132 
    133   object[Symbol.unscopables] = {x: true};
    134   with (object) {
    135     assertEquals(1, x);
    136     assertEquals(5, y);
    137     assertEquals(3, z);
    138   }
    139 
    140   object[Symbol.unscopables] = {x: 0, y: true};
    141   with (object) {
    142     assertEquals(1, x);
    143     assertEquals(2, y);
    144     assertEquals(3, z);
    145   }
    146 }
    147 runTest(TestBasics);
    148 
    149 
    150 function TestUnscopableChain(object) {
    151   var x = 1;
    152   object.x = 2;
    153 
    154   with (object) {
    155     assertEquals(2, x);
    156   }
    157 
    158   object[Symbol.unscopables] = {
    159     __proto__: {x: true}
    160   };
    161   with (object) {
    162     assertEquals(1, x);
    163   }
    164 }
    165 runTest(TestUnscopableChain);
    166 
    167 
    168 function TestBasicsSet(object) {
    169   var x = 1;
    170   object.x = 2;
    171 
    172   with (object) {
    173     assertEquals(2, x);
    174   }
    175 
    176   object[Symbol.unscopables] = {x: true};
    177   with (object) {
    178     assertEquals(1, x);
    179     x = 3;
    180     assertEquals(3, x);
    181   }
    182 
    183   assertEquals(3, x);
    184   assertEquals(2, object.x);
    185 }
    186 runTest(TestBasicsSet);
    187 
    188 
    189 function TestOnProto(object, proto) {
    190   var x = 1;
    191   var y = 2;
    192   var z = 3;
    193   proto.x = 4;
    194 
    195   Object.setPrototypeOf(object, proto);
    196   object.y = 5;
    197 
    198   with (object) {
    199     assertEquals(4, x);
    200     assertEquals(5, y);
    201     assertEquals(3, z);
    202   }
    203 
    204   proto[Symbol.unscopables] = {x: true};
    205   with (object) {
    206     assertEquals(1, x);
    207     assertEquals(5, y);
    208     assertEquals(3, z);
    209   }
    210 
    211   object[Symbol.unscopables] = {y: true};
    212   with (object) {
    213     assertEquals(4, x);
    214     assertEquals(2, y);
    215     assertEquals(3, z);
    216   }
    217 
    218   proto[Symbol.unscopables] = {y: true};
    219   object[Symbol.unscopables] = {x: true};
    220   with (object) {
    221     assertEquals(1, x);
    222     assertEquals(5, y);
    223     assertEquals(3, z);
    224   }
    225 }
    226 runTest(TestOnProto);
    227 
    228 
    229 function TestSetBlockedOnProto(object, proto) {
    230   var x = 1;
    231   object.x = 2;
    232 
    233   with (object) {
    234     assertEquals(2, x);
    235   }
    236 
    237   Object.setPrototypeOf(object, proto);
    238   proto[Symbol.unscopables] = {x: true};
    239   with (object) {
    240     assertEquals(1, x);
    241     x = 3;
    242     assertEquals(3, x);
    243   }
    244 
    245   assertEquals(3, x);
    246   assertEquals(2, object.x);
    247 }
    248 runTest(TestSetBlockedOnProto);
    249 
    250 
    251 function TestNonObject(object) {
    252   var x = 1;
    253   var y = 2;
    254   object.x = 3;
    255   object.y = 4;
    256 
    257   object[Symbol.unscopables] = 'xy';
    258   with (object) {
    259     assertEquals(3, x);
    260     assertEquals(4, y);
    261   }
    262 
    263   object[Symbol.unscopables] = null;
    264   with (object) {
    265     assertEquals(3, x);
    266     assertEquals(4, y);
    267   }
    268 }
    269 runTest(TestNonObject);
    270 
    271 
    272 function TestChangeDuringWith(object) {
    273   var x = 1;
    274   var y = 2;
    275   object.x = 3;
    276   object.y = 4;
    277 
    278   with (object) {
    279     assertEquals(3, x);
    280     assertEquals(4, y);
    281     object[Symbol.unscopables] = {x: true};
    282     assertEquals(1, x);
    283     assertEquals(4, y);
    284   }
    285 }
    286 runTest(TestChangeDuringWith);
    287 
    288 
    289 function TestChangeDuringWithWithPossibleOptimization(object) {
    290   var x = 1;
    291   object.x = 2;
    292   with (object) {
    293     for (var i = 0; i < 1000; i++) {
    294       if (i === 500) object[Symbol.unscopables] = {x: true};
    295       assertEquals(i < 500 ? 2: 1, x);
    296     }
    297   }
    298 }
    299 TestChangeDuringWithWithPossibleOptimization({});
    300 
    301 
    302 function TestChangeDuringWithWithPossibleOptimization2(object) {
    303   var x = 1;
    304   object.x = 2;
    305   object[Symbol.unscopables] = {x: true};
    306   with (object) {
    307     for (var i = 0; i < 1000; i++) {
    308       if (i === 500) delete object[Symbol.unscopables];
    309       assertEquals(i < 500 ? 1 : 2, x);
    310     }
    311   }
    312 }
    313 TestChangeDuringWithWithPossibleOptimization2({});
    314 
    315 
    316 function TestChangeDuringWithWithPossibleOptimization3(object) {
    317   var x = 1;
    318   object.x = 2;
    319   object[Symbol.unscopables] = {};
    320   with (object) {
    321     for (var i = 0; i < 1000; i++) {
    322       if (i === 500) object[Symbol.unscopables].x = true;
    323       assertEquals(i < 500 ? 2 : 1, x);
    324     }
    325   }
    326 }
    327 TestChangeDuringWithWithPossibleOptimization3({});
    328 
    329 
    330 function TestChangeDuringWithWithPossibleOptimization4(object) {
    331   var x = 1;
    332   object.x = 2;
    333   object[Symbol.unscopables] = {x: true};
    334   with (object) {
    335     for (var i = 0; i < 1000; i++) {
    336       if (i === 500) delete object[Symbol.unscopables].x;
    337       assertEquals(i < 500 ? 1 : 2, x);
    338     }
    339   }
    340 }
    341 TestChangeDuringWithWithPossibleOptimization4({});
    342 
    343 
    344 function TestAccessorReceiver(object, proto) {
    345   var x = 'local';
    346 
    347   Object.defineProperty(proto, 'x', {
    348     get: function() {
    349       assertEquals(object, this);
    350       return this.x_;
    351     },
    352     configurable: true
    353   });
    354   proto.x_ = 'proto';
    355 
    356   Object.setPrototypeOf(object, proto);
    357   proto.x_ = 'object';
    358 
    359   with (object) {
    360     assertEquals('object', x);
    361   }
    362 }
    363 runTest(TestAccessorReceiver);
    364 
    365 
    366 function TestUnscopablesGetter(object) {
    367   // This test gets really messy when object is the global since the assert
    368   // functions are properties on the global object and the call count gets
    369   // completely different.
    370   if (object === global) return;
    371 
    372   var x = 'local';
    373   object.x = 'object';
    374 
    375   var callCount = 0;
    376   Object.defineProperty(object, Symbol.unscopables, {
    377     get: function() {
    378       callCount++;
    379       return {};
    380     },
    381     configurable: true
    382   });
    383   with (object) {
    384     assertEquals('object', x);
    385   }
    386   // Once for HasBinding
    387   assertEquals(1, callCount);
    388 
    389   callCount = 0;
    390   Object.defineProperty(object, Symbol.unscopables, {
    391     get: function() {
    392       callCount++;
    393       return {x: true};
    394     },
    395     configurable: true
    396   });
    397   with (object) {
    398     assertEquals('local', x);
    399   }
    400   // Once for HasBinding
    401   assertEquals(1, callCount);
    402 
    403   callCount = 0;
    404   Object.defineProperty(object, Symbol.unscopables, {
    405     get: function() {
    406       callCount++;
    407       return callCount == 1 ? {} : {x: true};
    408     },
    409     configurable: true
    410   });
    411   with (object) {
    412     x = 1;
    413   }
    414   // Once for HasBinding
    415   assertEquals(1, callCount);
    416   assertEquals(1, object.x);
    417   assertEquals('local', x);
    418   with (object) {
    419     x = 2;
    420   }
    421   // One more HasBinding.
    422   assertEquals(2, callCount);
    423   assertEquals(1, object.x);
    424   assertEquals(2, x);
    425 }
    426 runTest(TestUnscopablesGetter);
    427 
    428 
    429 var global = this;
    430 function TestUnscopablesGetter2() {
    431   var x = 'local';
    432 
    433   var globalProto = Object.getPrototypeOf(global);
    434   var protos = [{}, [], function() {}, global];
    435   var objects = [{}, [], function() {}];
    436 
    437   protos.forEach(function(proto) {
    438     objects.forEach(function(object) {
    439       Object.defineProperty(proto, 'x', {
    440         get: function() {
    441           assertEquals(object, this);
    442           return 'proto';
    443         },
    444         configurable: true
    445       });
    446 
    447       object.__proto__ = proto;
    448       Object.defineProperty(object, 'x', {
    449         get: function() {
    450           assertEquals(object, this);
    451           return 'object';
    452         },
    453         configurable: true
    454       });
    455 
    456       with (object) {
    457         assertEquals('object', x);
    458       }
    459 
    460       object[Symbol.unscopables] = {x: true};
    461       with (object) {
    462         assertEquals('local', x);
    463       }
    464 
    465       delete proto[Symbol.unscopables];
    466       delete object[Symbol.unscopables];
    467     });
    468   });
    469 
    470   delete global.x;
    471   Object.setPrototypeOf(global, globalProto);
    472 }
    473 TestUnscopablesGetter2();
    474 
    475 
    476 function TestSetterOnBlacklisted(object, proto) {
    477   var x = 'local';
    478   Object.defineProperty(proto, 'x', {
    479     set: function(x) {
    480       assertUnreachable();
    481     },
    482     get: function() {
    483       return 'proto';
    484     },
    485     configurable: true
    486   });
    487   Object.setPrototypeOf(object, proto);
    488   Object.defineProperty(object, 'x', {
    489     get: function() {
    490       return this.x_;
    491     },
    492     set: function(x) {
    493       this.x_ = x;
    494     },
    495     configurable: true
    496   });
    497   object.x_ = 1;
    498 
    499   with (object) {
    500     x = 2;
    501     assertEquals(2, x);
    502   }
    503 
    504   assertEquals(2, object.x);
    505 
    506   object[Symbol.unscopables] = {x: true};
    507 
    508   with (object) {
    509     x = 3;
    510     assertEquals(3, x);
    511   }
    512 
    513   assertEquals(2, object.x);
    514 }
    515 runTest(TestSetterOnBlacklisted);
    516 
    517 
    518 function TestObjectsAsUnscopables(object, unscopables) {
    519   var x = 1;
    520   object.x = 2;
    521 
    522   with (object) {
    523     assertEquals(2, x);
    524     object[Symbol.unscopables] = unscopables;
    525     assertEquals(2, x);
    526   }
    527 }
    528 runTest(TestObjectsAsUnscopables);
    529 
    530 
    531 function TestAccessorOnUnscopables(object) {
    532   var x = 1;
    533   object.x = 2;
    534 
    535   var unscopables = {
    536     get x() {
    537       assertUnreachable();
    538     }
    539   };
    540 
    541   with (object) {
    542     assertEquals(2, x);
    543     object[Symbol.unscopables] = unscopables;
    544     assertEquals(1, x);
    545   }
    546 }
    547 runTest(TestAccessorOnUnscopables);
    548 
    549 
    550 function TestLengthUnscopables(object, proto) {
    551   var length = 2;
    552   with (object) {
    553     assertEquals(1, length);
    554     object[Symbol.unscopables] = {length: true};
    555     assertEquals(2, length);
    556     delete object[Symbol.unscopables];
    557     assertEquals(1, length);
    558   }
    559 }
    560 TestLengthUnscopables([1], Array.prototype);
    561 TestLengthUnscopables(function(x) {}, Function.prototype);
    562 TestLengthUnscopables(new String('x'), String.prototype);
    563 
    564 
    565 function TestFunctionNameUnscopables(object) {
    566   var name = 'local';
    567   with (object) {
    568     assertEquals('f', name);
    569     object[Symbol.unscopables] = {name: true};
    570     assertEquals('local', name);
    571     delete object[Symbol.unscopables];
    572     assertEquals('f', name);
    573   }
    574 }
    575 TestFunctionNameUnscopables(function f() {});
    576 
    577 
    578 function TestFunctionPrototypeUnscopables() {
    579   var prototype = 'local';
    580   var f = function() {};
    581   var g = function() {};
    582   Object.setPrototypeOf(f, g);
    583   var fp = f.prototype;
    584   var gp = g.prototype;
    585   with (f) {
    586     assertEquals(fp, prototype);
    587     f[Symbol.unscopables] = {prototype: true};
    588     assertEquals('local', prototype);
    589     delete f[Symbol.unscopables];
    590     assertEquals(fp, prototype);
    591   }
    592 }
    593 TestFunctionPrototypeUnscopables(function() {});
    594 
    595 
    596 function TestFunctionArgumentsUnscopables() {
    597   var func = function() {
    598     var arguments = 'local';
    599     var args = func.arguments;
    600     with (func) {
    601       assertEquals(args, arguments);
    602       func[Symbol.unscopables] = {arguments: true};
    603       assertEquals('local', arguments);
    604       delete func[Symbol.unscopables];
    605       assertEquals(args, arguments);
    606     }
    607   }
    608   func(1);
    609 }
    610 TestFunctionArgumentsUnscopables();
    611 
    612 
    613 function TestArgumentsLengthUnscopables() {
    614   var func = function() {
    615     var length = 'local';
    616     with (arguments) {
    617       assertEquals(1, length);
    618       arguments[Symbol.unscopables] = {length: true};
    619       assertEquals('local', length);
    620     }
    621   }
    622   func(1);
    623 }
    624 TestArgumentsLengthUnscopables();
    625 
    626 
    627 function TestFunctionCallerUnscopables() {
    628   var func = function() {
    629     var caller = 'local';
    630     with (func) {
    631       assertEquals(TestFunctionCallerUnscopables, caller);
    632       func[Symbol.unscopables] = {caller: true};
    633       assertEquals('local', caller);
    634       delete func[Symbol.unscopables];
    635       assertEquals(TestFunctionCallerUnscopables, caller);
    636     }
    637   }
    638   func(1);
    639 }
    640 TestFunctionCallerUnscopables();
    641 
    642 
    643 function TestGetUnscopablesGetterThrows() {
    644   var object = {
    645     get x() {
    646       assertUnreachable();
    647     }
    648   };
    649   function CustomError() {}
    650   Object.defineProperty(object, Symbol.unscopables, {
    651     get: function() {
    652       throw new CustomError();
    653     }
    654   });
    655   assertThrows(function() {
    656     with (object) {
    657       x;
    658     }
    659   }, CustomError);
    660 }
    661 TestGetUnscopablesGetterThrows();
    662