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 7assertEquals(1, Array.from.length); 8 9function 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 18var myCollectionCalled = false; 19function MyCollection(length) { 20 myCollectionCalled = true; 21 assertEquals(1, arguments.length); 22 assertEquals(5, length); 23} 24 25Array.from.call(MyCollection, {length: 5}); 26assertTrue(myCollectionCalled); 27 28// Assert that calling mapfn with / without thisArg in sloppy and strict modes 29// works as expected. 30var global = this; 31function non_strict(){ assertEquals(global, this); } 32function strict(){ "use strict"; assertEquals(void 0, this); } 33function strict_null(){ "use strict"; assertEquals(null, this); } 34Array.from([1], non_strict); 35Array.from([1], non_strict, void 0); 36Array.from([1], non_strict, null); 37Array.from([1], strict); 38Array.from([1], strict, void 0); 39Array.from([1], strict_null, null); 40 41function 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 137function Other() {} 138 139var boundFn = (function() {}).bind(Array, 27); 140 141testArrayFrom(Array, Array); 142testArrayFrom(null, Array); 143testArrayFrom({}, Array); 144testArrayFrom(Object, Object); 145testArrayFrom(Other, Other); 146testArrayFrom(Math.cos, Array); 147testArrayFrom(Math.cos.bind(Math), Array); 148testArrayFrom(boundFn, boundFn); 149 150// Assert that [[DefineOwnProperty]] is used in ArrayFrom, meaning a 151// setter isn't called, and a failed [[DefineOwnProperty]] will throw. 152var setterCalled = 0; 153function 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 160assertThrows(function () { Array.from.call(exotic, [1]); }, TypeError); 161// The setter wasn't called 162assertEquals(0, setterCalled); 163 164// Check that array properties defined are writable, enumerable, configurable 165function ordinary() { } 166var x = Array.from.call(ordinary, [2]); 167var xlength = Object.getOwnPropertyDescriptor(x, 'length'); 168assertEquals(1, xlength.value); 169assertEquals(true, xlength.writable); 170assertEquals(true, xlength.enumerable); 171assertEquals(true, xlength.configurable); 172var x0 = Object.getOwnPropertyDescriptor(x, 0); 173assertEquals(2, x0.value); 174assertEquals(true, xlength.writable); 175assertEquals(true, xlength.enumerable); 176assertEquals(true, xlength.configurable); 177 178})(); 179