1425bb815Sopenharmony_ci// Copyright JS Foundation and other contributors, http://js.foundation 2425bb815Sopenharmony_ci// 3425bb815Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4425bb815Sopenharmony_ci// you may not use this file except in compliance with the License. 5425bb815Sopenharmony_ci// You may obtain a copy of the License at 6425bb815Sopenharmony_ci// 7425bb815Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8425bb815Sopenharmony_ci// 9425bb815Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10425bb815Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS 11425bb815Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12425bb815Sopenharmony_ci// See the License for the specific language governing permissions and 13425bb815Sopenharmony_ci// limitations under the License. 14425bb815Sopenharmony_ci 15425bb815Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved. 16425bb815Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 17425bb815Sopenharmony_ci// found in the LICENSE file. 18425bb815Sopenharmony_ci 19425bb815Sopenharmony_ci// Some methods are taken from v8/test/mjsunit/mjsunit.js 20425bb815Sopenharmony_ci 21425bb815Sopenharmony_cifunction classOf(object) { 22425bb815Sopenharmony_ci // Argument must not be null or undefined. 23425bb815Sopenharmony_ci var string = Object.prototype.toString.call(object); 24425bb815Sopenharmony_ci // String has format [object <ClassName>]. 25425bb815Sopenharmony_ci return string.substring(8, string.length - 1); 26425bb815Sopenharmony_ci} 27425bb815Sopenharmony_ci 28425bb815Sopenharmony_ci/** 29425bb815Sopenharmony_ci * Compares two objects for key/value equality. 30425bb815Sopenharmony_ci * Returns true if they are equal, false otherwise. 31425bb815Sopenharmony_ci */ 32425bb815Sopenharmony_cifunction deepObjectEquals(a, b) { 33425bb815Sopenharmony_ci var aProps = Object.keys(a); 34425bb815Sopenharmony_ci aProps.sort(); 35425bb815Sopenharmony_ci var bProps = Object.keys(b); 36425bb815Sopenharmony_ci bProps.sort(); 37425bb815Sopenharmony_ci if (!deepEquals(aProps, bProps)) { 38425bb815Sopenharmony_ci return false; 39425bb815Sopenharmony_ci } 40425bb815Sopenharmony_ci for (var i = 0; i < aProps.length; i++) { 41425bb815Sopenharmony_ci if (!deepEquals(a[aProps[i]], b[aProps[i]])) { 42425bb815Sopenharmony_ci return false; 43425bb815Sopenharmony_ci } 44425bb815Sopenharmony_ci } 45425bb815Sopenharmony_ci return true; 46425bb815Sopenharmony_ci} 47425bb815Sopenharmony_ci 48425bb815Sopenharmony_civar assertInstanceof = function assertInstanceof(obj, type) { 49425bb815Sopenharmony_ci if (!(obj instanceof type)) { 50425bb815Sopenharmony_ci var actualTypeName = null; 51425bb815Sopenharmony_ci var actualConstructor = Object.getPrototypeOf(obj).constructor; 52425bb815Sopenharmony_ci if (typeof actualConstructor == "function") { 53425bb815Sopenharmony_ci actualTypeName = actualConstructor.name || String(actualConstructor); 54425bb815Sopenharmony_ci } print("Object <" + obj + "> is not an instance of <" + (type.name || type) + ">" + (actualTypeName ? " but of < " + actualTypeName + ">" : "")); 55425bb815Sopenharmony_ci } 56425bb815Sopenharmony_ci}; 57425bb815Sopenharmony_ci 58425bb815Sopenharmony_cifunction deepEquals(a, b) { 59425bb815Sopenharmony_ci if (a === b) { 60425bb815Sopenharmony_ci if (a === 0) return (1 / a) === (1 / b); 61425bb815Sopenharmony_ci return true; 62425bb815Sopenharmony_ci } 63425bb815Sopenharmony_ci if (typeof a != typeof b) return false; 64425bb815Sopenharmony_ci if (typeof a == "number") return isNaN(a) && isNaN(b); 65425bb815Sopenharmony_ci if (typeof a !== "object" && typeof a !== "function") return false; 66425bb815Sopenharmony_ci var objectClass = classOf(a); 67425bb815Sopenharmony_ci if (objectClass !== classOf(b)) return false; 68425bb815Sopenharmony_ci if (objectClass === "RegExp") { 69425bb815Sopenharmony_ci return (a.toString() === b.toString()); 70425bb815Sopenharmony_ci } 71425bb815Sopenharmony_ci if (objectClass === "Function") return false; 72425bb815Sopenharmony_ci if (objectClass === "Array") { 73425bb815Sopenharmony_ci var elementCount = 0; 74425bb815Sopenharmony_ci if (a.length != b.length) { 75425bb815Sopenharmony_ci return false; 76425bb815Sopenharmony_ci } 77425bb815Sopenharmony_ci for (var i = 0; i < a.length; i++) { 78425bb815Sopenharmony_ci if (!deepEquals(a[i], b[i])) 79425bb815Sopenharmony_ci return false; 80425bb815Sopenharmony_ci } 81425bb815Sopenharmony_ci return true; 82425bb815Sopenharmony_ci } 83425bb815Sopenharmony_ci if (objectClass == "String" || objectClass == "Number" || objectClass == "Boolean" || objectClass == "Date") { 84425bb815Sopenharmony_ci if (a.valueOf() !== b.valueOf()) return false; 85425bb815Sopenharmony_ci } 86425bb815Sopenharmony_ci return deepObjectEquals(a, b); 87425bb815Sopenharmony_ci} 88425bb815Sopenharmony_ci 89425bb815Sopenharmony_civar assertEquals = function assertEquals(expected, found, name_opt) { 90425bb815Sopenharmony_ci if (!deepEquals(found, expected)) { 91425bb815Sopenharmony_ci assert(false); 92425bb815Sopenharmony_ci } 93425bb815Sopenharmony_ci}; 94425bb815Sopenharmony_ci 95425bb815Sopenharmony_cifunction assertArrayLikeEquals(value, expected, type) { 96425bb815Sopenharmony_ci assertInstanceof(value, type); 97425bb815Sopenharmony_ci assert(expected.length === value.length); 98425bb815Sopenharmony_ci for (var i=0; i<value.length; ++i) { 99425bb815Sopenharmony_ci assertEquals(expected[i], value[i]); 100425bb815Sopenharmony_ci } 101425bb815Sopenharmony_ci} 102425bb815Sopenharmony_ci 103425bb815Sopenharmony_ciassert(1 === Array.from.length); 104425bb815Sopenharmony_ci 105425bb815Sopenharmony_ci// Assert that constructor is called with "length" for array-like objects 106425bb815Sopenharmony_ci 107425bb815Sopenharmony_civar myCollectionCalled = false; 108425bb815Sopenharmony_cifunction MyCollection(length) { 109425bb815Sopenharmony_ci myCollectionCalled = true; 110425bb815Sopenharmony_ci assert(1 === arguments.length); 111425bb815Sopenharmony_ci 112425bb815Sopenharmony_ci assert(5 === length); 113425bb815Sopenharmony_ci} 114425bb815Sopenharmony_ci 115425bb815Sopenharmony_ciArray.from.call(MyCollection, {length: 5}); 116425bb815Sopenharmony_ciassert(myCollectionCalled === true); 117425bb815Sopenharmony_ci// Assert that calling mapfn with / without thisArg in sloppy and strict modes 118425bb815Sopenharmony_ci// works as expected. 119425bb815Sopenharmony_ci 120425bb815Sopenharmony_civar global = this; 121425bb815Sopenharmony_cifunction non_strict(){ assert(global === this); } 122425bb815Sopenharmony_cifunction strict(){ "use strict"; assert(void 0 === this); } 123425bb815Sopenharmony_cifunction strict_null(){ "use strict"; assert(null === this); } 124425bb815Sopenharmony_ciArray.from([1], non_strict); 125425bb815Sopenharmony_ciArray.from([1], non_strict, void 0); 126425bb815Sopenharmony_ciArray.from([1], strict); 127425bb815Sopenharmony_ciArray.from([1], strict, void 0); 128425bb815Sopenharmony_ci 129425bb815Sopenharmony_cifunction testArrayFrom(thisArg, constructor) { 130425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, [], undefined), [], constructor); 131425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, NaN), [], constructor); 132425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, Infinity), [], constructor); 133425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 10000000), [], constructor); 134425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 'test'), ['t', 'e', 's', 't'], constructor); 135425bb815Sopenharmony_ci 136425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 137425bb815Sopenharmony_ci { length: 1, '0': { 'foo': 'bar' } }), [{'foo': 'bar'}], constructor); 138425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, { length: -1, '0': { 'foo': 'bar' } }), [], constructor); 139425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 140425bb815Sopenharmony_ci [ 'foo', 'bar', 'baz' ]), ['foo', 'bar', 'baz'], constructor); 141425bb815Sopenharmony_ci var kSet = new Set(['foo', 'bar', 'baz']); 142425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, kSet), ['foo', 'bar', 'baz'], constructor); 143425bb815Sopenharmony_ci var kMap = new Map(['foo', 'bar', 'baz'].entries()); 144425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, kMap), [[0, 'foo'], [1, 'bar'], [2, 'baz']], constructor); 145425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) { 146425bb815Sopenharmony_ci return this.filter(x); 147425bb815Sopenharmony_ci }, { 148425bb815Sopenharmony_ci filter: function(x) { return x.toUpperCase(); } 149425bb815Sopenharmony_ci }), ['T', 'E', 'S', 'T'], constructor); 150425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) { 151425bb815Sopenharmony_ci return x.toUpperCase(); 152425bb815Sopenharmony_ci }), ['T', 'E', 'S', 'T'], constructor); 153425bb815Sopenharmony_ci 154425bb815Sopenharmony_ci try { 155425bb815Sopenharmony_ci Array.from.call(thisArg, null); 156425bb815Sopenharmony_ci assert(false); 157425bb815Sopenharmony_ci } catch (e) { 158425bb815Sopenharmony_ci assert (e instanceof TypeError); 159425bb815Sopenharmony_ci } 160425bb815Sopenharmony_ci 161425bb815Sopenharmony_ci try { 162425bb815Sopenharmony_ci Array.from.call(thisArg, undefined); 163425bb815Sopenharmony_ci assert(false); 164425bb815Sopenharmony_ci } catch (e) { 165425bb815Sopenharmony_ci assert (e instanceof TypeError); 166425bb815Sopenharmony_ci } 167425bb815Sopenharmony_ci 168425bb815Sopenharmony_ci try { 169425bb815Sopenharmony_ci Array.from.call(thisArg, [], null); 170425bb815Sopenharmony_ci assert(false); 171425bb815Sopenharmony_ci } catch (e) { 172425bb815Sopenharmony_ci assert (e instanceof TypeError); 173425bb815Sopenharmony_ci } 174425bb815Sopenharmony_ci 175425bb815Sopenharmony_ci try { 176425bb815Sopenharmony_ci Array.from.call(thisArg, [], "noncallable"); 177425bb815Sopenharmony_ci assert(false); 178425bb815Sopenharmony_ci } catch (e) { 179425bb815Sopenharmony_ci assert (e instanceof TypeError); 180425bb815Sopenharmony_ci } 181425bb815Sopenharmony_ci 182425bb815Sopenharmony_ci var nullIterator = {}; 183425bb815Sopenharmony_ci nullIterator[Symbol.iterator] = null; 184425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, nullIterator), [], 185425bb815Sopenharmony_ci constructor); 186425bb815Sopenharmony_ci 187425bb815Sopenharmony_ci var nonObjIterator = {}; 188425bb815Sopenharmony_ci nonObjIterator[Symbol.iterator] = function() { return "nonObject"; }; 189425bb815Sopenharmony_ci 190425bb815Sopenharmony_ci try { 191425bb815Sopenharmony_ci Array.from.call(thisArg, nonObjIterator); 192425bb815Sopenharmony_ci assert(false); 193425bb815Sopenharmony_ci } catch (e) { 194425bb815Sopenharmony_ci assert (e instanceof TypeError); 195425bb815Sopenharmony_ci } 196425bb815Sopenharmony_ci 197425bb815Sopenharmony_ci try { 198425bb815Sopenharmony_ci Array.from.call(thisArg, [], null); 199425bb815Sopenharmony_ci assert(false); 200425bb815Sopenharmony_ci } catch (e) { 201425bb815Sopenharmony_ci assert (e instanceof TypeError); 202425bb815Sopenharmony_ci } 203425bb815Sopenharmony_ci 204425bb815Sopenharmony_ci // Ensure iterator is only accessed once, and only invoked once 205425bb815Sopenharmony_ci var called = false; 206425bb815Sopenharmony_ci var arr = [1, 2, 3]; 207425bb815Sopenharmony_ci var obj = {}; 208425bb815Sopenharmony_ci 209425bb815Sopenharmony_ci // Test order --- only get iterator method once 210425bb815Sopenharmony_ci function testIterator() { 211425bb815Sopenharmony_ci assert(called !== "@@iterator should be called only once"); 212425bb815Sopenharmony_ci called = true; 213425bb815Sopenharmony_ci assert(obj === this); 214425bb815Sopenharmony_ci return arr[Symbol.iterator](); 215425bb815Sopenharmony_ci } 216425bb815Sopenharmony_ci var getCalled = false; 217425bb815Sopenharmony_ci Object.defineProperty(obj, Symbol.iterator, { 218425bb815Sopenharmony_ci get: function() { 219425bb815Sopenharmony_ci assert(getCalled !== "@@iterator should be accessed only once"); 220425bb815Sopenharmony_ci getCalled = true; 221425bb815Sopenharmony_ci return testIterator; 222425bb815Sopenharmony_ci }, 223425bb815Sopenharmony_ci set: function() { 224425bb815Sopenharmony_ci // "@@iterator should not be set" 225425bb815Sopenharmony_ci assert(false); 226425bb815Sopenharmony_ci } 227425bb815Sopenharmony_ci }); 228425bb815Sopenharmony_ci assertArrayLikeEquals(Array.from.call(thisArg, obj), [1, 2, 3], constructor); 229425bb815Sopenharmony_ci} 230425bb815Sopenharmony_ci 231425bb815Sopenharmony_cifunction Other() {} 232425bb815Sopenharmony_ci 233425bb815Sopenharmony_civar boundFn = (function() {}).bind(Array, 27); 234425bb815Sopenharmony_ci 235425bb815Sopenharmony_citestArrayFrom(Array, Array); 236425bb815Sopenharmony_citestArrayFrom(null, Array); 237425bb815Sopenharmony_citestArrayFrom({}, Array); 238425bb815Sopenharmony_citestArrayFrom(Object, Object); 239425bb815Sopenharmony_citestArrayFrom(Other, Other); 240425bb815Sopenharmony_citestArrayFrom(Math.cos, Array); 241425bb815Sopenharmony_citestArrayFrom(boundFn, boundFn); 242425bb815Sopenharmony_ci 243425bb815Sopenharmony_ci// Assert that [[DefineOwnProperty]] is used in ArrayFrom, meaning a 244425bb815Sopenharmony_ci// setter isn't called, and a failed [[DefineOwnProperty]] will throw. 245425bb815Sopenharmony_civar setterCalled = 0; 246425bb815Sopenharmony_cifunction exotic() { 247425bb815Sopenharmony_ci Object.defineProperty(this, '0', { 248425bb815Sopenharmony_ci get: function() { return 2; }, 249425bb815Sopenharmony_ci set: function() { setterCalled++; } 250425bb815Sopenharmony_ci }); 251425bb815Sopenharmony_ci} 252425bb815Sopenharmony_ci 253425bb815Sopenharmony_ci// Non-configurable properties can't be overwritten with DefineOwnProperty 254425bb815Sopenharmony_ci// The setter wasn't called 255425bb815Sopenharmony_citry { 256425bb815Sopenharmony_ci Array.from.call(exotic, [1]); 257425bb815Sopenharmony_ci assert(false); 258425bb815Sopenharmony_ci} catch (e) { 259425bb815Sopenharmony_ci assert (e instanceof TypeError); 260425bb815Sopenharmony_ci} 261425bb815Sopenharmony_ci 262425bb815Sopenharmony_ciassert( 0 === setterCalled); 263425bb815Sopenharmony_ci 264425bb815Sopenharmony_ci// Non-callable iterators should cause a TypeError before calling the target 265425bb815Sopenharmony_ci// constructor. 266425bb815Sopenharmony_ciitems = {}; 267425bb815Sopenharmony_ciitems[Symbol.iterator] = 7; 268425bb815Sopenharmony_cifunction TestError() {} 269425bb815Sopenharmony_cifunction ArrayLike() { throw new TestError() } 270425bb815Sopenharmony_ci 271425bb815Sopenharmony_citry { 272425bb815Sopenharmony_ci Array.from.call(ArrayLike, items); 273425bb815Sopenharmony_ci assert(false); 274425bb815Sopenharmony_ci} catch (e) { 275425bb815Sopenharmony_ci assert (e instanceof TypeError); 276425bb815Sopenharmony_ci} 277425bb815Sopenharmony_ci 278425bb815Sopenharmony_ci// Check that array properties defined are writable, enumerable, configurable 279425bb815Sopenharmony_cifunction ordinary() { } 280425bb815Sopenharmony_civar x = Array.from.call(ordinary, [2]); 281425bb815Sopenharmony_civar xlength = Object.getOwnPropertyDescriptor(x, 'length'); 282425bb815Sopenharmony_ciassert(1 === xlength.value); 283425bb815Sopenharmony_ciassert(true === xlength.writable); 284425bb815Sopenharmony_ciassert(true === xlength.enumerable); 285425bb815Sopenharmony_ciassert(true === xlength.configurable); 286425bb815Sopenharmony_civar x0 = Object.getOwnPropertyDescriptor(x, 0); 287425bb815Sopenharmony_ciassert(2 === x0.value); 288425bb815Sopenharmony_ciassert(true === xlength.writable); 289425bb815Sopenharmony_ciassert(true === xlength.enumerable); 290425bb815Sopenharmony_ciassert(true === xlength.configurable); 291425bb815Sopenharmony_ci 292425bb815Sopenharmony_ci/* Test iterator close */ 293425bb815Sopenharmony_cifunction __createIterableObject (arr, methods) { 294425bb815Sopenharmony_ci methods = methods || {}; 295425bb815Sopenharmony_ci if (typeof Symbol !== 'function' || !Symbol.iterator) { 296425bb815Sopenharmony_ci return {}; 297425bb815Sopenharmony_ci } 298425bb815Sopenharmony_ci arr.length++; 299425bb815Sopenharmony_ci var iterator = { 300425bb815Sopenharmony_ci next: function() { 301425bb815Sopenharmony_ci return { value: arr.shift(), done: arr.length <= 0 }; 302425bb815Sopenharmony_ci }, 303425bb815Sopenharmony_ci 'return': methods['return'], 304425bb815Sopenharmony_ci 'throw': methods['throw'] 305425bb815Sopenharmony_ci }; 306425bb815Sopenharmony_ci var iterable = {}; 307425bb815Sopenharmony_ci iterable[Symbol.iterator] = function () { return iterator; }; 308425bb815Sopenharmony_ci return iterable; 309425bb815Sopenharmony_ci}; 310425bb815Sopenharmony_ci 311425bb815Sopenharmony_cifunction close1() { 312425bb815Sopenharmony_ci var closed = false; 313425bb815Sopenharmony_ci var iter = __createIterableObject([1, 2, 3], { 314425bb815Sopenharmony_ci 'return': function() { closed = true; return {}; } 315425bb815Sopenharmony_ci }); 316425bb815Sopenharmony_ci 317425bb815Sopenharmony_ci try { 318425bb815Sopenharmony_ci Array.from(iter, x => { throw 5 }); 319425bb815Sopenharmony_ci assert(false); 320425bb815Sopenharmony_ci } catch (e) { 321425bb815Sopenharmony_ci assert(e === 5); 322425bb815Sopenharmony_ci } 323425bb815Sopenharmony_ci 324425bb815Sopenharmony_ci return closed; 325425bb815Sopenharmony_ci} 326425bb815Sopenharmony_ciassert(close1()); 327425bb815Sopenharmony_ci 328425bb815Sopenharmony_cifunction close2() { 329425bb815Sopenharmony_ci var closed = false; 330425bb815Sopenharmony_ci var iter = __createIterableObject([1, 2, 3], { 331425bb815Sopenharmony_ci 'return': function() { closed = true; throw 6 } 332425bb815Sopenharmony_ci }); 333425bb815Sopenharmony_ci 334425bb815Sopenharmony_ci try { 335425bb815Sopenharmony_ci Array.from(iter, x => { throw 5 }); 336425bb815Sopenharmony_ci assert(false); 337425bb815Sopenharmony_ci } catch (e) { 338425bb815Sopenharmony_ci assert(e === 5); 339425bb815Sopenharmony_ci } 340425bb815Sopenharmony_ci 341425bb815Sopenharmony_ci return closed; 342425bb815Sopenharmony_ci} 343425bb815Sopenharmony_ciassert(close2()); 344425bb815Sopenharmony_ci 345