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 // Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
      6 
      7 
      8 
      9 // Array.of makes real arrays.
     10 
     11 function check(a) {
     12     assertEquals(Object.getPrototypeOf(a), Array.prototype);
     13     assertEquals(Array.isArray(a), true);
     14     a[9] = 9;
     15     assertEquals(a.length, 10);
     16 }
     17 
     18 
     19 check(Array.of());
     20 check(Array.of(0));
     21 check(Array.of(0, 1, 2));
     22 var f = Array.of;
     23 check(f());
     24 
     25 
     26 // Array.of basics
     27 
     28 var a = Array.of();
     29 
     30 assertEquals(a.length, 0);
     31 a = Array.of(undefined, null, 3.14, []);
     32 assertEquals(a, [undefined, null, 3.14, []]);
     33 a = [];
     34 for (var i = 0; i < 1000; i++)
     35     a[i] = i;
     36 assertEquals(Array.of.apply(null, a), a);
     37 
     38 
     39 // Array.of does not leave holes
     40 
     41 assertEquals(Array.of(undefined), [undefined]);
     42 assertEquals(Array.of(undefined, undefined), [undefined, undefined]);
     43 assertEquals(Array.of.apply(null, [,,undefined]), [undefined, undefined, undefined]);
     44 assertEquals(Array.of.apply(null, Array(4)), [undefined, undefined, undefined, undefined]);
     45 
     46 
     47 // Array.of can be transplanted to other classes.
     48 
     49 var hits = 0;
     50 function Bag() {
     51     hits++;
     52 }
     53 Bag.of = Array.of;
     54 
     55 hits = 0;
     56 var actual = Bag.of("zero", "one");
     57 assertEquals(hits, 1);
     58 
     59 hits = 0;
     60 var expected = new Bag;
     61 expected[0] = "zero";
     62 expected[1] = "one";
     63 expected.length = 2;
     64 assertEquals(areSame(actual, expected), true);
     65 
     66 hits = 0;
     67 actual = Array.of.call(Bag, "zero", "one");
     68 assertEquals(hits, 1);
     69 assertEquals(areSame(actual, expected), true);
     70 
     71 function areSame(object, array) {
     72     var result = object.length == array.length;
     73     for (var i = 0; i < object.length; i++) {
     74         result = result && object[i] == array[i];
     75     }
     76     return result;
     77 }
     78 
     79 
     80 // Array.of does not trigger prototype setters.
     81 // (It defines elements rather than assigning to them.)
     82 
     83 var status = "pass";
     84 Object.defineProperty(Array.prototype, "0", {set: function(v) {status = "FAIL 1"}});
     85 assertEquals(Array.of(1)[0], 1);
     86 assertEquals(status, "pass");
     87 
     88 Object.defineProperty(Bag.prototype, "0", {set: function(v) {status = "FAIL 2"}});
     89 assertEquals(Bag.of(1)[0], 1);
     90 assertEquals(status, "pass");
     91 
     92 
     93 // Array.of passes the number of arguments to the constructor it calls.
     94 
     95 var hits = 0;
     96 
     97 function Herd(n) {
     98     assertEquals(arguments.length, 1);
     99     assertEquals(n, 5);
    100     hits++;
    101 }
    102 
    103 Herd.of = Array.of;
    104 Herd.of("sheep", "cattle", "elephants", "whales", "seals");
    105 assertEquals(hits, 1);
    106 
    107 
    108 // Array.of calls a "length" setter if one is present.
    109 
    110 var hits = 0;
    111 var lastObj = null, lastVal = undefined;
    112 function setter(v) {
    113     hits++;
    114     lastObj = this;
    115     lastVal = v;
    116 }
    117 
    118 // when the setter is on the new object
    119 function Pack() {
    120     Object.defineProperty(this, "length", {set: setter});
    121 }
    122 Pack.of = Array.of;
    123 var pack = Pack.of("wolves", "cards", "cigarettes", "lies");
    124 assertEquals(lastObj, pack);
    125 assertEquals(lastVal, 4);
    126 
    127 // when the setter is on the new object's prototype
    128 function Bevy() {}
    129 Object.defineProperty(Bevy.prototype, "length", {set: setter});
    130 Bevy.of = Array.of;
    131 var bevy = Bevy.of("quail");
    132 assertEquals(lastObj, bevy);
    133 assertEquals(lastVal, 1);
    134 
    135 
    136 // Array.of does a strict assignment to the new object's .length.
    137 // The assignment is strict even if the code we're calling from is not strict.
    138 
    139 function Empty() {}
    140 Empty.of = Array.of;
    141 Object.defineProperty(Empty.prototype, "length", {get: function() { return 0; }});
    142 
    143 var nothing = new Empty;
    144 nothing.length = 2;  // no exception; this is not a strict mode assignment
    145 
    146 assertThrows(function() { Empty.of(); }, TypeError);
    147 
    148 
    149 // Check superficial features of Array.of.
    150 
    151 var desc = Object.getOwnPropertyDescriptor(Array, "of");
    152 
    153 assertEquals(desc.configurable, true);
    154 assertEquals(desc.enumerable, false);
    155 assertEquals(desc.writable, true);
    156 assertEquals(Array.of.length, 0);
    157 assertThrows(function() { new Array.of() }, TypeError);  // not a constructor
    158 
    159 // When the this-value passed in is not a constructor, the result is an array.
    160 [
    161   undefined,
    162   null,
    163   false,
    164   "cow",
    165   NaN,
    166   67,
    167   Infinity,
    168   -Infinity,
    169   Math.cos, // builtin functions with no [[Construct]] slot
    170   Math.cos.bind(Math) // bound builtin functions with no [[Construct]] slot
    171 ].forEach(function(val) {
    172     assertEquals(Array.isArray(Array.of.call(val, val)), true);
    173 });
    174 
    175 
    176 (function testBoundConstructor() {
    177   var boundFn = (function() {}).bind(null);
    178   var instance = Array.of.call(boundFn, 1, 2, 3);
    179   assertEquals(instance.length, 3);
    180   assertEquals(instance instanceof boundFn, true);
    181   assertEquals(Array.isArray(instance), false);
    182 })();
    183 
    184 (function testDefinesOwnProperty() {
    185   // Assert that [[DefineOwnProperty]] is used in ArrayFrom, meaning a
    186   // setter isn't called, and a failed [[DefineOwnProperty]] will throw.
    187   var setterCalled = 0;
    188   function exotic() {
    189     Object.defineProperty(this,  '0', {
    190       get: function() { return 2; },
    191       set: function() { setterCalled++; }
    192     });
    193   }
    194   // Non-configurable properties can't be overwritten with DefineOwnProperty
    195   assertThrows(function () { Array.of.call(exotic, 1); }, TypeError);
    196   // The setter wasn't called
    197   assertEquals(0, setterCalled);
    198 
    199   // Check that array properties defined are writable, enumerable, configurable
    200   function ordinary() { }
    201   var x = Array.of.call(ordinary, 2);
    202   var xlength = Object.getOwnPropertyDescriptor(x, 'length');
    203   assertEquals(1, xlength.value);
    204   assertEquals(true, xlength.writable);
    205   assertEquals(true, xlength.enumerable);
    206   assertEquals(true, xlength.configurable);
    207   var x0 = Object.getOwnPropertyDescriptor(x, 0);
    208   assertEquals(2, x0.value);
    209   assertEquals(true, xlength.writable);
    210   assertEquals(true, xlength.enumerable);
    211   assertEquals(true, xlength.configurable);
    212 })();
    213