ladybird/Userland/Libraries/LibJS/Tests/loops/for-in-basic.js
Shannon Booth 30ab198b40 LibJS: Create const variables in ForIn/OfBodyEvaluation in strict mode
Our implementation of environment.CreateImmutableBinding(name, true)
in this AO was not correctly initializing const variables in strict
mode. This would mean that constant declarations in for loop bodies
would not throw if they were modified.

To fix this, add a new parameter to CreateVariable to set strict mode.
Also remove the vm.is_strict mode check here, as it doesn't look like
anywhere in the spec will change strict mode depending on whether the
script itself is running in script mode or not.

This fixes two of our test-js tests, no change to test262.
2023-09-21 16:19:05 +02:00

132 lines
3.1 KiB
JavaScript

test("iterate through empty string", () => {
const a = [];
for (const property in "") {
a.push(property);
}
expect(a).toEqual([]);
});
test("iterate through number", () => {
const a = [];
for (const property in 123) {
a.push(property);
}
expect(a).toEqual([]);
});
test("iterate through empty object", () => {
const a = [];
for (const property in {}) {
a.push(property);
}
expect(a).toEqual([]);
});
test("iterate through string", () => {
const a = [];
for (const property in "hello") {
a.push(property);
}
expect(a).toEqual(["0", "1", "2", "3", "4"]);
});
test("iterate through object", () => {
const a = [];
for (const property in { a: 1, b: 2, c: 2 }) {
a.push(property);
}
expect(a).toEqual(["a", "b", "c"]);
});
test("iterate through undefined", () => {
for (const property in undefined) {
expect.fail();
}
});
test("use already-declared variable", () => {
var property;
for (property in "abc");
expect(property).toBe("2");
});
test("allow binding patterns", () => {
const expected = [
["1", "3", []],
["s", undefined, []],
["l", "n", ["g", "N", "a", "m", "e"]],
];
let counter = 0;
for (let [a, , b, ...c] in { 123: 1, sm: 2, longName: 3 }) {
expect(a).toBe(expected[counter][0]);
expect(b).toBe(expected[counter][1]);
expect(c).toEqual(expected[counter][2]);
counter++;
}
expect(counter).toBe(3);
});
describe("special left hand sides", () => {
test("allow member expression as variable", () => {
const f = {};
for (f.a in "abc");
expect(f.a).toBe("2");
});
test("allow member expression of function call", () => {
const b = {};
function f() {
return b;
}
for (f().a in "abc");
expect(f().a).toBe("2");
expect(b.a).toBe("2");
});
test.xfail("call function is allowed in parsing but fails in runtime", () => {
function f() {
expect().fail();
}
// Does not fail since it does not iterate
expect("for (f() in []);").toEvalTo(undefined);
expect(() => {
eval("for (f() in [0]) { expect().fail() }");
}).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment");
});
test("Cannot change constant declaration in body", () => {
const vals = [];
for (const v in [1, 2]) {
expect(() => v++).toThrowWithMessage(TypeError, "Invalid assignment to const variable");
vals.push(v);
}
expect(vals).toEqual(["0", "1"]);
});
});
test("remove properties while iterating", () => {
const from = [1, 2, 3];
const to = [];
for (const prop in from) {
to.push(prop);
from.pop();
}
expect(to).toEqual(["0", "1"]);
});
test("duplicated properties in prototype", () => {
const object = { a: 1 };
const proto = { a: 2 };
Object.setPrototypeOf(object, proto);
const a = [];
for (const prop in object) {
a.push(prop);
}
expect(a).toEqual(["a"]);
});