blob: c4648d5f211f893ec4c2b22ff88a858a6e3924c9 [file] [log] [blame]
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array ];
if (typeof SharedArrayBuffer != "undefined")
constructors.push(sharedConstructor(Int8Array),
sharedConstructor(Uint8Array),
sharedConstructor(Int16Array),
sharedConstructor(Uint16Array),
sharedConstructor(Int32Array),
sharedConstructor(Uint32Array),
sharedConstructor(Float32Array),
sharedConstructor(Float64Array));
for (var constructor of constructors) {
// %TypedArray%.from throws if the argument is undefined or null.
assertThrowsInstanceOf(() => constructor.from(), TypeError);
assertThrowsInstanceOf(() => constructor.from(undefined), TypeError);
assertThrowsInstanceOf(() => constructor.from(null), TypeError);
// %TypedArray%.from throws if an element can't be defined on the new object.
function ObjectWithReadOnlyElement() {
Object.defineProperty(this, "0", {value: null});
this.length = 0;
}
ObjectWithReadOnlyElement.from = constructor.from;
assertDeepEq(ObjectWithReadOnlyElement.from([]), new ObjectWithReadOnlyElement);
assertThrowsInstanceOf(() => ObjectWithReadOnlyElement.from([1]), TypeError);
// The same, but via preventExtensions.
function InextensibleObject() {
Object.preventExtensions(this);
}
InextensibleObject.from = constructor.from;
assertThrowsInstanceOf(() => InextensibleObject.from([1]), TypeError);
// The same, but via a readonly property on its __proto__.
function ObjectWithReadOnlyElementOnProto() {
return Object.create({
get 0(){}
});
}
ObjectWithReadOnlyElementOnProto.from = constructor.from;
assertThrowsInstanceOf(() => ObjectWithReadOnlyElementOnProto.from([1]), TypeError);
// Unlike Array.from, %TypedArray%.from doesn't get or set the length property.
function ObjectWithThrowingLengthGetterSetter() {
Object.defineProperty(this, "length", {
configurable: true,
get() { throw new RangeError("getter!"); },
set() { throw new RangeError("setter!"); }
});
}
ObjectWithThrowingLengthGetterSetter.from = constructor.from;
assertEq(ObjectWithThrowingLengthGetterSetter.from(["foo"])[0], "foo");
// %TypedArray%.from throws if mapfn is neither callable nor undefined.
assertThrowsInstanceOf(() => constructor.from([3, 4, 5], {}), TypeError);
assertThrowsInstanceOf(() => constructor.from([3, 4, 5], "also not a function"), TypeError);
assertThrowsInstanceOf(() => constructor.from([3, 4, 5], null), TypeError);
// Even if the function would not have been called.
assertThrowsInstanceOf(() => constructor.from([], JSON), TypeError);
// If mapfn is not undefined and not callable, the error happens before anything else.
// Before calling the constructor, before touching the arrayLike.
var log = "";
function C() {
log += "C";
obj = this;
}
var p = new Proxy({}, {
has: function () { log += "1"; },
get: function () { log += "2"; },
getOwnPropertyDescriptor: function () { log += "3"; }
});
assertThrowsInstanceOf(() => constructor.from.call(C, p, {}), TypeError);
assertEq(log, "");
// If mapfn throws, the new object has already been created.
var arrayish = {
get length() { log += "l"; return 1; },
get 0() { log += "0"; return "q"; }
};
log = "";
var exc = {surprise: "ponies"};
assertThrowsValue(() => constructor.from.call(C, arrayish, () => { throw exc; }), exc);
assertEq(log, "lC0");
assertEq(obj instanceof C, true);
// It's a TypeError if the @@iterator property is a primitive (except null and undefined).
for (var primitive of ["foo", 17, Symbol(), true]) {
assertThrowsInstanceOf(() => constructor.from({[Symbol.iterator] : primitive}), TypeError);
}
assertDeepEq(constructor.from({[Symbol.iterator]: null}), new constructor());
assertDeepEq(constructor.from({[Symbol.iterator]: undefined}), new constructor());
// It's a TypeError if the iterator's .next() method returns a primitive.
for (var primitive of [undefined, null, "foo", 17, Symbol(), true]) {
assertThrowsInstanceOf(
() => constructor.from({
[Symbol.iterator]() {
return {next() { return primitive; }};
}
}),
TypeError);
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);