Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions interpreter/interpreter_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -16456,6 +16456,102 @@ test "B.2: Array length set huge via defineProperty stays sparse" {
json_inspect(output, content=["1000000", "1", "undefined"])
}

///|
test "array defineProperty sparse Int64 index stays sparse" {
let src =
#|var arr = [];
#|console.log(Reflect.defineProperty(arr, "2147483647", { value: "tail", configurable: true }));
#|console.log(arr.length);
#|console.log(arr["2147483647"]);
#|console.log(arr[0]);
let output = run_output(src)
json_inspect(output, content=["true", "2147483648", "tail", "undefined"])
}

///|
test "array defineProperty below non-writable Int64 length succeeds" {
let src =
#|var arr = [];
#|Object.defineProperty(arr, "length", { value: 3000000000 });
#|Object.defineProperty(arr, "length", { writable: false });
#|console.log(Reflect.defineProperty(arr, "0", { value: 1, configurable: true }));
#|console.log(arr[0]);
#|console.log(arr.length);
let output = run_output(src)
json_inspect(output, content=["true", "1", "3000000000"])
}

///|
test "array ownKeys orders sparse Int64 index before length" {
let src =
#|var arr = [];
#|arr[0] = "zero";
#|Reflect.defineProperty(arr, "2147483648", { value: "tail", configurable: true });
#|arr.name = "named";
#|console.log(Reflect.ownKeys(arr).join("|"));
let output = run_output(src)
json_inspect(output, content=["0|2147483648|length|name"])
}

///|
test "array dense assignment updates stale sparse length override" {
let src =
#|var arr = [];
#|Object.defineProperty(arr, "length", { value: 150000 });
#|arr[99999] = 1;
#|arr[150000] = 2;
#|console.log(arr.length);
#|console.log(arr[150000]);
let output = run_output(src)
json_inspect(output, content=["150001", "2"])
}

///|
test "array species result rejects CreateDataPropertyOrThrow" {
let src =
#|function attempt(label, thunk) {
#| try { thunk(); console.log(label + ":ok"); }
#| catch (e) { console.log(label + ":" + e.name); }
#|}
#|var source = [1];
#|source.constructor = {
#| [Symbol.species]: function() { return Object.preventExtensions({}); }
#|};
#|attempt("map", function() { source.map(function(x) { return x; }); });
#|attempt("slice", function() { source.slice(0, 1); });
#|attempt("concat", function() { source.concat([2]); });
let output = run_output(src)
json_inspect(output, content=[
"map:TypeError", "slice:TypeError", "concat:TypeError",
])
}

///|
test "array splice length overflow throws before species" {
let src =
#|var calls = [];
#|var array = [];
#|array.constructor = {};
#|Object.defineProperty(array.constructor, Symbol.species, {
#| get: function() {
#| calls.push("species");
#| return function(n) { calls.push("ctor:" + n); return []; };
#| }
#|});
#|var source = new Proxy(array, {
#| get: function(t, k, r) {
#| if (k === "length") { calls.push("length"); return 9007199254740991; }
#| calls.push(String(k));
#| return Reflect.get(t, k, r);
#| }
#|});
#|try { Array.prototype.splice.call(source, 0, 0, "x"); console.log("ok"); }
#|catch (e) { console.log(e.name); }
#|console.log(calls.join("|"));
let output = run_output(src)
json_inspect(output, content=["TypeError", "length"])
}

///|
/// IteratorClose: iterator.return() called when for-of body throws (ForOfStmt)
test "IteratorClose: body throw calls iterator return (ForOfStmt)" {
Expand Down Expand Up @@ -19043,3 +19139,67 @@ test "Object.setPrototypeOf handles Map, Set, and Promise receivers (#452)" {
"true", "undefined", "true", "undefined", "true", "true",
])
}

///|
test "array includes uses Int64 ToLength and fromIndex near max safe integer" {
let src =
#|var obj = {
#| "9007199254740990": "needle",
#| length: 9007199254740991
#|};
#|console.log(Array.prototype.includes.call(obj, "needle", 9007199254740990));
#|console.log(Array.prototype.includes.call(obj, "missing", 9007199254740990));
#|
let output = run_output(src)
json_inspect(output, content=["true", "false"])
}

///|
test "array relative indices preserve negative infinity" {
let src =
#|var obj = { 0: "x", length: 9007199254740991 };
#|console.log(Array.prototype.at.call(obj, -Infinity));
#|console.log(Array.prototype.lastIndexOf.call(obj, "x", -Infinity));
#|console.log(Array.prototype.includes.call(obj, "x", -Infinity));
#|console.log(Array.prototype.at.call(obj, -9007199254740992));
#|try { Array.prototype.with.call(obj, -Infinity, "y"); console.log("ok"); }
#|catch (e) { console.log(e.name); }
#|
let output = run_output(src)
json_inspect(output, content=[
"undefined", "-1", "true", "undefined", "RangeError",
])
}

///|
test "array slice copies sparse properties near max safe integer" {
let src =
#|var obj = {
#| "9007199254740989": "a",
#| "9007199254740990": "b",
#| length: 9007199254740993
#|};
#|var result = Array.prototype.slice.call(obj, 9007199254740989);
#|console.log(result.length);
#|console.log(result[0] + "," + result[1]);
#|
let output = run_output(src)
json_inspect(output, content=["2", "a,b"])
}

///|
test "array toSpliced clamps ToLength before copying high sparse tail" {
let src =
#|var obj = {
#| "9007199254740989": "a",
#| "9007199254740990": "b",
#| "9007199254740991": "ignored",
#| length: 9007199254741012
#|};
#|var result = Array.prototype.toSpliced.call(obj, 0, 9007199254740989);
#|console.log(result.length);
#|console.log(result[0] + "," + result[1]);
#|
let output = run_output(src)
json_inspect(output, content=["2", "a,b"])
}
Loading