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 (function() { 6 7 assertEquals(1, Array.from.length); 8 9 function assertArrayLikeEquals(value, expected, type) { 10 assertInstanceof(value, type); 11 assertEquals(expected.length, value.length); 12 for (var i=0; i<value.length; ++i) { 13 assertEquals(expected[i], value[i]); 14 } 15 } 16 17 // Assert that constructor is called with "length" for array-like objects 18 var myCollectionCalled = false; 19 function MyCollection(length) { 20 myCollectionCalled = true; 21 assertEquals(1, arguments.length); 22 assertEquals(5, length); 23 } 24 25 Array.from.call(MyCollection, {length: 5}); 26 assertTrue(myCollectionCalled); 27 28 // Assert that calling mapfn with / without thisArg in sloppy and strict modes 29 // works as expected. 30 var global = this; 31 function non_strict(){ assertEquals(global, this); } 32 function strict(){ "use strict"; assertEquals(void 0, this); } 33 function strict_null(){ "use strict"; assertEquals(null, this); } 34 Array.from([1], non_strict); 35 Array.from([1], non_strict, void 0); 36 Array.from([1], non_strict, null); 37 Array.from([1], strict); 38 Array.from([1], strict, void 0); 39 Array.from([1], strict_null, null); 40 41 function testArrayFrom(thisArg, constructor) { 42 assertArrayLikeEquals(Array.from.call(thisArg, [], undefined), [], 43 constructor); 44 assertArrayLikeEquals(Array.from.call(thisArg, NaN), [], constructor); 45 assertArrayLikeEquals(Array.from.call(thisArg, Infinity), [], constructor); 46 assertArrayLikeEquals(Array.from.call(thisArg, 10000000), [], constructor); 47 assertArrayLikeEquals(Array.from.call(thisArg, 'test'), ['t', 'e', 's', 't'], 48 constructor); 49 50 assertArrayLikeEquals(Array.from.call(thisArg, 51 { length: 1, '0': { 'foo': 'bar' } }), [{'foo': 'bar'}], constructor); 52 53 assertArrayLikeEquals(Array.from.call(thisArg, 54 { length: -1, '0': { 'foo': 'bar' } }), [], constructor); 55 56 assertArrayLikeEquals(Array.from.call(thisArg, 57 [ 'foo', 'bar', 'baz' ]), ['foo', 'bar', 'baz'], constructor); 58 59 var kSet = new Set(['foo', 'bar', 'baz']); 60 assertArrayLikeEquals(Array.from.call(thisArg, kSet), ['foo', 'bar', 'baz'], 61 constructor); 62 63 var kMap = new Map(['foo', 'bar', 'baz'].entries()); 64 assertArrayLikeEquals(Array.from.call(thisArg, kMap), 65 [[0, 'foo'], [1, 'bar'], [2, 'baz']], constructor); 66 67 68 function* generator() { 69 yield 'a'; 70 yield 'b'; 71 yield 'c'; 72 } 73 74 assertArrayLikeEquals(Array.from.call(thisArg, generator()), 75 ['a', 'b', 'c'], constructor); 76 77 // Mozilla: 78 // Array.from on a string handles surrogate pairs correctly. 79 var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF 80 assertArrayLikeEquals(Array.from.call(thisArg, gclef), [gclef], constructor); 81 assertArrayLikeEquals(Array.from.call(thisArg, gclef + " G"), 82 [gclef, " ", "G"], constructor); 83 84 assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) { 85 return this.filter(x); 86 }, { 87 filter: function(x) { return x.toUpperCase(); } 88 }), ['T', 'E', 'S', 'T'], constructor); 89 assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) { 90 return x.toUpperCase(); 91 }), ['T', 'E', 'S', 'T'], constructor); 92 93 assertThrows(function() { Array.from.call(thisArg, null); }, TypeError); 94 assertThrows(function() { Array.from.call(thisArg, undefined); }, TypeError); 95 assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError); 96 assertThrows(function() { Array.from.call(thisArg, [], "noncallable"); }, 97 TypeError); 98 99 var nullIterator = {}; 100 nullIterator[Symbol.iterator] = null; 101 assertArrayLikeEquals(Array.from.call(thisArg, nullIterator), [], 102 constructor); 103 104 var nonObjIterator = {}; 105 nonObjIterator[Symbol.iterator] = function() { return "nonObject"; }; 106 assertThrows(function() { Array.from.call(thisArg, nonObjIterator); }, 107 TypeError); 108 109 assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError); 110 111 // Ensure iterator is only accessed once, and only invoked once 112 var called = false; 113 var arr = [1, 2, 3]; 114 var obj = {}; 115 116 // Test order --- only get iterator method once 117 function testIterator() { 118 assertFalse(called, "@@iterator should be called only once"); 119 called = true; 120 assertEquals(obj, this); 121 return arr[Symbol.iterator](); 122 } 123 var getCalled = false; 124 Object.defineProperty(obj, Symbol.iterator, { 125 get: function() { 126 assertFalse(getCalled, "@@iterator should be accessed only once"); 127 getCalled = true; 128 return testIterator; 129 }, 130 set: function() { 131 assertUnreachable("@@iterator should not be set"); 132 } 133 }); 134 assertArrayLikeEquals(Array.from.call(thisArg, obj), [1, 2, 3], constructor); 135 } 136 137 function Other() {} 138 139 var boundFn = (function() {}).bind(Array, 27); 140 141 testArrayFrom(Array, Array); 142 testArrayFrom(null, Array); 143 testArrayFrom({}, Array); 144 testArrayFrom(Object, Object); 145 testArrayFrom(Other, Other); 146 testArrayFrom(Math.cos, Array); 147 testArrayFrom(Math.cos.bind(Math), Array); 148 testArrayFrom(boundFn, boundFn); 149 150 // Assert that [[DefineOwnProperty]] is used in ArrayFrom, meaning a 151 // setter isn't called, and a failed [[DefineOwnProperty]] will throw. 152 var setterCalled = 0; 153 function exotic() { 154 Object.defineProperty(this, '0', { 155 get: function() { return 2; }, 156 set: function() { setterCalled++; } 157 }); 158 } 159 // Non-configurable properties can't be overwritten with DefineOwnProperty 160 assertThrows(function () { Array.from.call(exotic, [1]); }, TypeError); 161 // The setter wasn't called 162 assertEquals(0, setterCalled); 163 164 // Check that array properties defined are writable, enumerable, configurable 165 function ordinary() { } 166 var x = Array.from.call(ordinary, [2]); 167 var xlength = Object.getOwnPropertyDescriptor(x, 'length'); 168 assertEquals(1, xlength.value); 169 assertEquals(true, xlength.writable); 170 assertEquals(true, xlength.enumerable); 171 assertEquals(true, xlength.configurable); 172 var x0 = Object.getOwnPropertyDescriptor(x, 0); 173 assertEquals(2, x0.value); 174 assertEquals(true, xlength.writable); 175 assertEquals(true, xlength.enumerable); 176 assertEquals(true, xlength.configurable); 177 178 })(); 179