summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/TypedArray/from_errors.js
blob: 281b1b512922ebd21f6225a47bdcb47df4ed8f7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
for (var constructor of anyTypedArrayConstructors) {
    // %TypedArray%.from throws if the argument is undefined or null.
    assertThrowsInstanceOf(() => constructor.from(), TypeError);
    assertThrowsInstanceOf(() => constructor.from(undefined), TypeError);
    assertThrowsInstanceOf(() => constructor.from(null), TypeError);

    // Unlike Array.from, %TypedArray%.from doesn't get or set the length property.
    function ObjectWithThrowingLengthGetterSetter(...rest) {
        var ta = new constructor(...rest);
        Object.defineProperty(ta, "length", {
            configurable: true,
            get() { throw new RangeError("getter!"); },
            set() { throw new RangeError("setter!"); }
        });
        return ta;
    }
    ObjectWithThrowingLengthGetterSetter.from = constructor.from;
    assertEq(ObjectWithThrowingLengthGetterSetter.from([123])[0], 123);

    // %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 = "";
    var obj;
    function C(...rest) {
        log += "C";
        obj = new constructor(...rest);
        return obj;
    }
    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 constructor, 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);