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
16425bb815Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved.
17425bb815Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
18425bb815Sopenharmony_ci// found in the LICENSE file.
19425bb815Sopenharmony_ci
20425bb815Sopenharmony_ci// Test the ES2015 @@species feature
21425bb815Sopenharmony_ci
22425bb815Sopenharmony_ci'use strict';
23425bb815Sopenharmony_ci
24425bb815Sopenharmony_ci// Subclasses of Array construct themselves under map, etc
25425bb815Sopenharmony_ci
26425bb815Sopenharmony_ciclass MyArray extends Array { }
27425bb815Sopenharmony_ci
28425bb815Sopenharmony_cifunction assertEquals(a, b) {
29425bb815Sopenharmony_ci  assert(a === b);
30425bb815Sopenharmony_ci}
31425bb815Sopenharmony_ci
32425bb815Sopenharmony_ciassertEquals(MyArray, new MyArray().map(()=>{}).constructor);
33425bb815Sopenharmony_ciassertEquals(MyArray, new MyArray().filter(()=>{}).constructor);
34425bb815Sopenharmony_ciassertEquals(MyArray, new MyArray().slice().constructor);
35425bb815Sopenharmony_ciassertEquals(MyArray, new MyArray().splice().constructor);
36425bb815Sopenharmony_ciassertEquals(MyArray, new MyArray().concat([1]).constructor);
37425bb815Sopenharmony_ciassertEquals(1, new MyArray().concat([1])[0]);
38425bb815Sopenharmony_ci
39425bb815Sopenharmony_ci// Subclasses can override @@species to return the another class
40425bb815Sopenharmony_ci
41425bb815Sopenharmony_ciclass MyOtherArray extends Array {
42425bb815Sopenharmony_ci  static get [Symbol.species]() { return MyArray; }
43425bb815Sopenharmony_ci}
44425bb815Sopenharmony_ci
45425bb815Sopenharmony_ciassertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor);
46425bb815Sopenharmony_ciassertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor);
47425bb815Sopenharmony_ciassertEquals(MyArray, new MyOtherArray().slice().constructor);
48425bb815Sopenharmony_ciassertEquals(MyArray, new MyOtherArray().splice().constructor);
49425bb815Sopenharmony_ciassertEquals(MyArray, new MyOtherArray().concat().constructor);
50425bb815Sopenharmony_ci
51425bb815Sopenharmony_ci// Array  methods on non-arrays return arrays
52425bb815Sopenharmony_ci
53425bb815Sopenharmony_ciclass MyNonArray extends Array {
54425bb815Sopenharmony_ci  static get [Symbol.species]() { return MyObject; }
55425bb815Sopenharmony_ci}
56425bb815Sopenharmony_ci
57425bb815Sopenharmony_ciclass MyObject { }
58425bb815Sopenharmony_ci
59425bb815Sopenharmony_ciassertEquals(MyObject,
60425bb815Sopenharmony_ci             Array.prototype.map.call(new MyNonArray(), ()=>{}).constructor);
61425bb815Sopenharmony_ciassertEquals(MyObject,
62425bb815Sopenharmony_ci             Array.prototype.filter.call(new MyNonArray(), ()=>{}).constructor);
63425bb815Sopenharmony_ciassertEquals(MyObject,
64425bb815Sopenharmony_ci             Array.prototype.slice.call(new MyNonArray()).constructor);
65425bb815Sopenharmony_ciassertEquals(MyObject,
66425bb815Sopenharmony_ci             Array.prototype.splice.call(new MyNonArray()).constructor);
67425bb815Sopenharmony_ciassertEquals(MyObject,
68425bb815Sopenharmony_ci             Array.prototype.concat.call(new MyNonArray()).constructor);
69425bb815Sopenharmony_ci
70425bb815Sopenharmony_ciassertEquals(undefined,
71425bb815Sopenharmony_ci             Array.prototype.map.call(new MyNonArray(), ()=>{}).length);
72425bb815Sopenharmony_ciassertEquals(undefined,
73425bb815Sopenharmony_ci             Array.prototype.filter.call(new MyNonArray(), ()=>{}).length);
74425bb815Sopenharmony_ci// slice, splice, and concat actually do explicitly define the length.
75425bb815Sopenharmony_ciassertEquals(0, Array.prototype.slice.call(new MyNonArray()).length);
76425bb815Sopenharmony_ciassertEquals(0, Array.prototype.splice.call(new MyNonArray()).length);
77425bb815Sopenharmony_ciassertEquals(1, Array.prototype.concat.call(new MyNonArray(), ()=>{}).length);
78425bb815Sopenharmony_ci
79425bb815Sopenharmony_ci// Defaults when constructor or @@species is missing or non-constructor
80425bb815Sopenharmony_ci
81425bb815Sopenharmony_ciclass MyDefaultArray extends Array {
82425bb815Sopenharmony_ci  static get [Symbol.species]() { return undefined; }
83425bb815Sopenharmony_ci}
84425bb815Sopenharmony_ciassertEquals(Array, new MyDefaultArray().map(()=>{}).constructor);
85425bb815Sopenharmony_ci
86425bb815Sopenharmony_ciclass MyOtherDefaultArray extends Array { }
87425bb815Sopenharmony_ciassertEquals(MyOtherDefaultArray,
88425bb815Sopenharmony_ci             new MyOtherDefaultArray().map(()=>{}).constructor);
89425bb815Sopenharmony_ciMyOtherDefaultArray.prototype.constructor = undefined;
90425bb815Sopenharmony_ciassertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor);
91425bb815Sopenharmony_ciassertEquals(Array, new MyOtherDefaultArray().concat().constructor);
92425bb815Sopenharmony_ci
93425bb815Sopenharmony_ci// Exceptions propagated when getting constructor @@species throws
94425bb815Sopenharmony_ci
95425bb815Sopenharmony_ciclass SpeciesError extends Error { }
96425bb815Sopenharmony_ciclass ConstructorError extends Error { }
97425bb815Sopenharmony_ciclass MyThrowingArray extends Array {
98425bb815Sopenharmony_ci  static get [Symbol.species]() { throw new SpeciesError; }
99425bb815Sopenharmony_ci}
100425bb815Sopenharmony_ci
101425bb815Sopenharmony_cifunction assertThrows (a, b) {
102425bb815Sopenharmony_ci  try {
103425bb815Sopenharmony_ci    a();
104425bb815Sopenharmony_ci  } catch (e) {
105425bb815Sopenharmony_ci    assert(e instanceof b);
106425bb815Sopenharmony_ci  }
107425bb815Sopenharmony_ci}
108425bb815Sopenharmony_ci
109425bb815Sopenharmony_ciassertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError);
110425bb815Sopenharmony_ciObject.defineProperty(MyThrowingArray.prototype, 'constructor', {
111425bb815Sopenharmony_ci    get() { throw new ConstructorError; }
112425bb815Sopenharmony_ci});
113425bb815Sopenharmony_ciassertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError);
114425bb815Sopenharmony_ci
115425bb815Sopenharmony_ci// Previously unexpected errors from setting properties in arrays throw
116425bb815Sopenharmony_ci
117425bb815Sopenharmony_ciclass FrozenArray extends Array {
118425bb815Sopenharmony_ci  constructor(...args) {
119425bb815Sopenharmony_ci    super(...args);
120425bb815Sopenharmony_ci    Object.freeze(this);
121425bb815Sopenharmony_ci  }
122425bb815Sopenharmony_ci}
123425bb815Sopenharmony_ciassertThrows(() => new FrozenArray([1]).map(()=>0), TypeError);
124425bb815Sopenharmony_ciassertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError);
125425bb815Sopenharmony_ciassertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError);
126425bb815Sopenharmony_ciassertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError);
127425bb815Sopenharmony_ciassertThrows(() => new FrozenArray([]).concat([1]), TypeError);
128425bb815Sopenharmony_ci
129425bb815Sopenharmony_ci// Verify call counts and constructor parameters
130425bb815Sopenharmony_ci
131425bb815Sopenharmony_civar count;
132425bb815Sopenharmony_civar params;
133425bb815Sopenharmony_ciclass MyObservedArray extends Array {
134425bb815Sopenharmony_ci  constructor(...args) {
135425bb815Sopenharmony_ci    super(...args);
136425bb815Sopenharmony_ci    params = args;
137425bb815Sopenharmony_ci  }
138425bb815Sopenharmony_ci  static get [Symbol.species]() {
139425bb815Sopenharmony_ci    count++
140425bb815Sopenharmony_ci    return this;
141425bb815Sopenharmony_ci  }
142425bb815Sopenharmony_ci}
143425bb815Sopenharmony_ci
144425bb815Sopenharmony_cifunction assertArrayEquals(value, expected, type) {
145425bb815Sopenharmony_ci  assert(expected.length === value.length);
146425bb815Sopenharmony_ci  for (var i=0; i<value.length; ++i) {
147425bb815Sopenharmony_ci    assertEquals(expected[i], value[i]);
148425bb815Sopenharmony_ci  }
149425bb815Sopenharmony_ci}
150425bb815Sopenharmony_ci
151425bb815Sopenharmony_cicount = 0;
152425bb815Sopenharmony_ciparams = undefined;
153425bb815Sopenharmony_ciassertEquals(MyObservedArray,
154425bb815Sopenharmony_ci             new MyObservedArray().map(()=>{}).constructor);
155425bb815Sopenharmony_ciassertEquals(1, count);
156425bb815Sopenharmony_ciassertArrayEquals([0], params);
157425bb815Sopenharmony_ci
158425bb815Sopenharmony_cicount = 0;
159425bb815Sopenharmony_ciparams = undefined;
160425bb815Sopenharmony_ciassertEquals(MyObservedArray,
161425bb815Sopenharmony_ci             new MyObservedArray().filter(()=>{}).constructor);
162425bb815Sopenharmony_ciassertEquals(1, count);
163425bb815Sopenharmony_ciassertArrayEquals([0], params);
164425bb815Sopenharmony_ci
165425bb815Sopenharmony_cicount = 0;
166425bb815Sopenharmony_ciparams = undefined;
167425bb815Sopenharmony_ciassertEquals(MyObservedArray,
168425bb815Sopenharmony_ci             new MyObservedArray().concat().constructor);
169425bb815Sopenharmony_ciassertEquals(1, count);
170425bb815Sopenharmony_ciassertArrayEquals([0], params);
171425bb815Sopenharmony_ci
172425bb815Sopenharmony_cicount = 0;
173425bb815Sopenharmony_ciparams = undefined;
174425bb815Sopenharmony_ciassertEquals(MyObservedArray,
175425bb815Sopenharmony_ci             new MyObservedArray().slice().constructor);
176425bb815Sopenharmony_ciassertEquals(1, count);
177425bb815Sopenharmony_ciassertArrayEquals([0], params);
178425bb815Sopenharmony_ci
179425bb815Sopenharmony_cicount = 0;
180425bb815Sopenharmony_ciparams = undefined;
181425bb815Sopenharmony_ciassertEquals(MyObservedArray,
182425bb815Sopenharmony_ci             new MyObservedArray().splice().constructor);
183425bb815Sopenharmony_ciassertEquals(1, count);
184425bb815Sopenharmony_ciassertArrayEquals([0], params);
185