diff options
Diffstat (limited to 'js/src/tests/non262/Array/species.js')
-rw-r--r-- | js/src/tests/non262/Array/species.js | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/js/src/tests/non262/Array/species.js b/js/src/tests/non262/Array/species.js new file mode 100644 index 0000000000..3669c286f6 --- /dev/null +++ b/js/src/tests/non262/Array/species.js @@ -0,0 +1,182 @@ +var BUGNUMBER = 1165052; +var summary = 'Use ArraySpeciesCreate in Array.prototype.{concat,filter,map,slice,splice}.'; + +print(BUGNUMBER + ": " + summary); + +function test(funcName, args, expectedLength, expectedLogs) { + // modified @@species + function FakeArray(n) { + this.length = n; + } + var a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: FakeArray + }; + var b = a[funcName](...args); + assertEq(b.constructor, FakeArray); + + function FakeArrayWithSpecies(n) { + this.length = n; + } + FakeArrayWithSpecies[Symbol.species] = FakeArrayWithSpecies; + a = [1, 2, 3, 4, 5]; + a.constructor = FakeArrayWithSpecies; + b = a[funcName](...args); + assertEq(b.constructor, FakeArrayWithSpecies); + + function FakeArrayWithHook(n) { + return new Proxy(new FakeArray(n), { + set(that, name, value) { + logs += "set:" + name + ":" + value + ","; + return true; + }, + defineProperty(that, name, desc) { + logs += "define:" + name + ":" + desc.value + ":" + desc.configurable + ":" + desc.enumerable + ":" + desc.writable + ","; + return true; + } + }); + } + var logs = ""; + var ctorProxy = new Proxy({}, { + get(that, name) { + logs += "c-get:" + name.toString() + ","; + if (name == Symbol.species) + return FakeArrayWithHook; + + return undefined; + } + }); + a = new Proxy([1, 2, 3, 4, 5], { + get(that, name) { + logs += "get:" + name.toString() + ","; + if (name == "constructor") + return ctorProxy; + return that[name]; + } + }); + b = a[funcName](...args); + assertEq(b.constructor, FakeArray); + assertEq(Object.keys(b).sort().join(","), "length"); + assertEq(b.length, expectedLength); + assertEq(logs, expectedLogs); + + // no @@species + a = [1, 2, 3, 4, 5]; + a.constructor = FakeArray; + b = a[funcName](...args); + assertEq(b.constructor, Array); + + a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: undefined + }; + b = a[funcName](...args); + assertEq(b.constructor, Array); + + a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: null + }; + b = a[funcName](...args); + assertEq(b.constructor, Array); + + // invalid @@species + for (var species of [0, 1.1, true, false, "a", /a/, Symbol.iterator, [], {}]) { + a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: species + }; + assertThrowsInstanceOf(() => a[funcName](...args), TypeError); + } + + // undefined constructor + a = [1, 2, 3, 4, 5]; + a.constructor = undefined; + b = a[funcName](...args); + assertEq(b.constructor, Array); + + // invalid constructor + for (var ctor of [null, 0, 1.1, true, false, "a", Symbol.iterator]) { + a = [1, 2, 3, 4, 5]; + a.constructor = ctor; + assertThrowsInstanceOf(() => a[funcName](...args), TypeError); + } + + // not an array + a = new Proxy({ + 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, + length: 5, + [funcName]: Array.prototype[funcName] + }, { + get(that, name) { + assertEq(name !== "constructor", true); + return that[name]; + } + }); + b = a[funcName](...args); + assertEq(b.constructor, Array); + + // @@species from different global + var g = newGlobal(); + g.eval("function FakeArray(n) { this.length = n; }"); + a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: g.FakeArray + }; + b = a[funcName](...args); + assertEq(b.constructor, g.FakeArray); + + a = [1, 2, 3, 4, 5]; + a.constructor = { + [Symbol.species]: g.Array + }; + b = a[funcName](...args); + assertEq(b.constructor, g.Array); + + // constructor from different global + g.eval("function FakeArrayWithSpecies(n) { this.length = n; }"); + g.eval("FakeArrayWithSpecies[Symbol.species] = FakeArrayWithSpecies;"); + a = [1, 2, 3, 4, 5]; + a.constructor = g.FakeArrayWithSpecies; + b = a[funcName](...args); + assertEq(b.constructor, g.FakeArrayWithSpecies); + + g.eval("var a = [1, 2, 3, 4, 5];"); + b = Array.prototype[funcName].apply(g.a, args); + assertEq(b.constructor, Array); + + // running in different global + b = g.a[funcName](...args); + assertEq(b.constructor, g.Array); + + // subclasses + // not-modified @@species + eval(` +class ${funcName}Class extends Array { +} +a = new ${funcName}Class(1, 2, 3, 4, 5); +b = a[funcName](...args); +assertEq(b.constructor, ${funcName}Class); +`); + + // modified @@species + eval(` +class ${funcName}Class2 extends Array { + static get [Symbol.species]() { + return Date; + } +} +a = new ${funcName}Class2(1, 2, 3, 4, 5); +b = a[funcName](...args); +assertEq(b.constructor, Date); +`); +} + +test("concat", [], 0, "get:concat,get:constructor,c-get:Symbol(Symbol.species),get:Symbol(Symbol.isConcatSpreadable),get:length,get:0,define:0:1:true:true:true,get:1,define:1:2:true:true:true,get:2,define:2:3:true:true:true,get:3,define:3:4:true:true:true,get:4,define:4:5:true:true:true,set:length:5,"); +test("filter", [x => x % 2], 0, "get:filter,get:length,get:constructor,c-get:Symbol(Symbol.species),get:0,define:0:1:true:true:true,get:1,get:2,define:1:3:true:true:true,get:3,get:4,define:2:5:true:true:true,"); +test("map", [x => x * 2], 5, "get:map,get:length,get:constructor,c-get:Symbol(Symbol.species),get:0,define:0:2:true:true:true,get:1,define:1:4:true:true:true,get:2,define:2:6:true:true:true,get:3,define:3:8:true:true:true,get:4,define:4:10:true:true:true,"); +test("slice", [], 5, "get:slice,get:length,get:constructor,c-get:Symbol(Symbol.species),get:0,define:0:1:true:true:true,get:1,define:1:2:true:true:true,get:2,define:2:3:true:true:true,get:3,define:3:4:true:true:true,get:4,define:4:5:true:true:true,set:length:5,"); +test("splice", [0, 5], 5, "get:splice,get:length,get:constructor,c-get:Symbol(Symbol.species),get:0,define:0:1:true:true:true,get:1,define:1:2:true:true:true,get:2,define:2:3:true:true:true,get:3,define:3:4:true:true:true,get:4,define:4:5:true:true:true,set:length:5,"); + +if (typeof reportCompare === "function") + reportCompare(true, true); |