OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Flags: --harmony-species | 5 // Flags: --harmony-species |
6 | 6 |
7 // Test the ES2015 @@species feature | 7 // Test the ES2015 @@species feature |
8 | 8 |
9 'use strict'; | 9 'use strict'; |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 | 28 |
29 // @@species is defined with distinct getters | 29 // @@species is defined with distinct getters |
30 assertEquals(classesWithSpecies.length, | 30 assertEquals(classesWithSpecies.length, |
31 new Set(classesWithSpecies.map(constructor => | 31 new Set(classesWithSpecies.map(constructor => |
32 Object.getOwnPropertyDescriptor( | 32 Object.getOwnPropertyDescriptor( |
33 constructor, Symbol.species).get) | 33 constructor, Symbol.species).get) |
34 ).size); | 34 ).size); |
35 | 35 |
36 for (let constructor of classesWithoutSpecies) | 36 for (let constructor of classesWithoutSpecies) |
37 assertEquals(undefined, constructor[Symbol.species]); | 37 assertEquals(undefined, constructor[Symbol.species]); |
| 38 |
| 39 // Subclasses of Array and %TypedArray% construct themselves under map, etc |
| 40 |
| 41 class MyArray extends Array { } |
| 42 |
| 43 assertEquals(MyArray, new MyArray().map(()=>{}).constructor); |
| 44 assertEquals(MyArray, new MyArray().filter(()=>{}).constructor); |
| 45 assertEquals(MyArray, new MyArray().concat().constructor); |
| 46 assertEquals(MyArray, new MyArray().slice().constructor); |
| 47 assertEquals(MyArray, new MyArray().splice().constructor); |
| 48 |
| 49 var typedArrayConstructors = [ |
| 50 Uint8Array, |
| 51 Int8Array, |
| 52 Uint16Array, |
| 53 Int16Array, |
| 54 Uint32Array, |
| 55 Int32Array, |
| 56 Uint8ClampedArray, |
| 57 Float32Array, |
| 58 Float64Array |
| 59 ]; |
| 60 |
| 61 for (let constructor of typedArrayConstructors) { |
| 62 class MyTypedArray extends constructor { } |
| 63 assertEquals(MyTypedArray, new MyTypedArray().map(()=>0).constructor); |
| 64 assertEquals(MyTypedArray, new MyTypedArray().filter(()=>{}).constructor); |
| 65 assertEquals(MyTypedArray, new MyTypedArray().slice().constructor); |
| 66 } |
| 67 |
| 68 // Subclasses can override @@species to return the another class |
| 69 |
| 70 class MyOtherArray extends Array { |
| 71 static get [Symbol.species]() { return MyArray; } |
| 72 } |
| 73 |
| 74 assertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor); |
| 75 assertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor); |
| 76 assertEquals(MyArray, new MyOtherArray().concat().constructor); |
| 77 assertEquals(MyArray, new MyOtherArray().slice().constructor); |
| 78 assertEquals(MyArray, new MyOtherArray().splice().constructor); |
| 79 |
| 80 for (let constructor of typedArrayConstructors) { |
| 81 class MyTypedArray extends constructor { } |
| 82 class MyOtherTypedArray extends constructor { |
| 83 static get [Symbol.species]() { return MyTypedArray; } |
| 84 } |
| 85 assertEquals(MyTypedArray, new MyOtherTypedArray().map(()=>0).constructor); |
| 86 assertEquals(MyTypedArray, new MyOtherTypedArray().filter(()=>{}).constructor)
; |
| 87 assertEquals(MyTypedArray, new MyOtherTypedArray().slice().constructor); |
| 88 } |
| 89 |
| 90 // TypedArray too-short and non-TypedArray error checking |
| 91 |
| 92 for (let constructor of typedArrayConstructors) { |
| 93 class MyShortTypedArray extends constructor { |
| 94 constructor(length) { super(length - 1); } |
| 95 } |
| 96 assertThrows(() => new MyShortTypedArray(5).map(()=>0), TypeError); |
| 97 assertThrows(() => new MyShortTypedArray(5).filter(()=>true), TypeError); |
| 98 assertThrows(() => new MyShortTypedArray(5).slice(), TypeError); |
| 99 |
| 100 class MyNonTypedArray extends constructor { |
| 101 static get [Symbol.species]() { return Array; } |
| 102 } |
| 103 assertThrows(() => new MyNonTypedArray().map(()=>0), TypeError); |
| 104 assertThrows(() => new MyNonTypedArray().filter(()=>{}), TypeError); |
| 105 assertThrows(() => new MyNonTypedArray().slice(), TypeError); |
| 106 } |
| 107 |
| 108 // Array methods on non-arrays return arrays |
| 109 |
| 110 class MyNonArray extends Array { |
| 111 static get [Symbol.species]() { return MyObject; } |
| 112 } |
| 113 |
| 114 class MyObject { } |
| 115 |
| 116 assertEquals(MyObject, Array.prototype.map.call(new MyNonArray(), ()=>{}).constr
uctor); |
| 117 assertEquals(MyObject, Array.prototype.filter.call(new MyNonArray(), ()=>{}).con
structor); |
| 118 assertEquals(MyObject, Array.prototype.concat.call(new MyNonArray()).constructor
); |
| 119 assertEquals(MyObject, Array.prototype.slice.call(new MyNonArray()).constructor)
; |
| 120 assertEquals(MyObject, Array.prototype.splice.call(new MyNonArray()).constructor
); |
| 121 |
| 122 assertEquals(undefined, Array.prototype.map.call(new MyNonArray(), ()=>{}).lengt
h); |
| 123 assertEquals(undefined, Array.prototype.filter.call(new MyNonArray(), ()=>{}).le
ngth); |
| 124 assertEquals(undefined, Array.prototype.concat.call(new MyNonArray()).length); |
| 125 // slice and splice actually do explicitly define the length for some reason |
| 126 assertEquals(0, Array.prototype.slice.call(new MyNonArray()).length); |
| 127 assertEquals(0, Array.prototype.splice.call(new MyNonArray()).length); |
| 128 |
| 129 // Cross-realm Arrays build same-realm arrays |
| 130 |
| 131 var realm = Realm.create(); |
| 132 assertEquals(Array, Array.prototype.map.call(Realm.eval(realm, "[]"), ()=>{}).co
nstructor); |
| 133 assertFalse(Array === Realm.eval(realm, "[]").map(()=>{}).constructor); |
| 134 assertFalse(Array === Realm.eval(realm, "[].map(()=>{}).constructor")); |
| 135 |
| 136 // Defaults when constructor or @@species is missing or non-constructor |
| 137 |
| 138 class MyDefaultArray extends Array { |
| 139 static get [Symbol.species]() { return undefined; } |
| 140 } |
| 141 assertEquals(Array, new MyDefaultArray().map(()=>{}).constructor); |
| 142 |
| 143 class MyOtherDefaultArray extends Array { } |
| 144 assertEquals(MyOtherDefaultArray, new MyOtherDefaultArray().map(()=>{}).construc
tor); |
| 145 MyOtherDefaultArray.prototype.constructor = undefined; |
| 146 assertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor); |
| 147 |
| 148 for (let constructor of typedArrayConstructors) { |
| 149 class MyDefaultTypedArray extends constructor { |
| 150 static get [Symbol.species]() { return undefined; } |
| 151 } |
| 152 assertEquals(constructor, new MyDefaultTypedArray().map(()=>0).constructor); |
| 153 |
| 154 class MyOtherDefaultTypedArray extends constructor { } |
| 155 assertEquals(MyOtherDefaultTypedArray, new MyOtherDefaultTypedArray().map(()=>
0).constructor); |
| 156 MyOtherDefaultTypedArray.prototype.constructor = undefined; |
| 157 assertEquals(constructor, new MyOtherDefaultTypedArray().map(()=>0).constructo
r); |
| 158 } |
| 159 |
| 160 // Exceptions propagated when getting constructor @@species throws |
| 161 |
| 162 class SpeciesError extends Error { } |
| 163 class ConstructorError extends Error { } |
| 164 class MyThrowingArray extends Array { |
| 165 static get [Symbol.species]() { throw new SpeciesError; } |
| 166 } |
| 167 assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError); |
| 168 Object.defineProperty(MyThrowingArray.prototype, 'constructor', { |
| 169 get() { throw new ConstructorError; } |
| 170 }); |
| 171 assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError); |
| 172 |
| 173 for (let constructor of typedArrayConstructors) { |
| 174 class MyThrowingArray extends constructor { |
| 175 static get [Symbol.species]() { throw new SpeciesError; } |
| 176 } |
| 177 assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError); |
| 178 Object.defineProperty(MyThrowingArray.prototype, 'constructor', { |
| 179 get() { throw new ConstructorError; } |
| 180 }); |
| 181 assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError); |
| 182 } |
| 183 |
| 184 // Previously unexpected errors from setting properties in arrays throw |
| 185 |
| 186 class FrozenArray extends Array { |
| 187 constructor(...args) { |
| 188 super(...args); |
| 189 Object.freeze(this); |
| 190 } |
| 191 } |
| 192 assertThrows(() => new FrozenArray([1]).map(()=>0), TypeError); |
| 193 assertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError); |
| 194 assertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError); |
| 195 assertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError); |
| 196 assertThrows(() => new FrozenArray([1]).concat(), TypeError); |
| 197 |
| 198 // ArrayBuffer.prototype.slice makes subclass and checks length |
| 199 |
| 200 class MyArrayBuffer extends ArrayBuffer { } |
| 201 assertEquals(MyArrayBuffer, new MyArrayBuffer(0).slice().constructor); |
| 202 |
| 203 class MyShortArrayBuffer extends ArrayBuffer { |
| 204 constructor(length) { super(length - 1); } |
| 205 } |
| 206 assertThrows(() => new MyShortArrayBuffer(5).slice(0, 4), TypeError); |
OLD | NEW |