ladybird/Userland/Libraries/LibJS/Tests/try-finally-break.js
Luke Wilde 08750f69e4 LibJS: Add thorough tests for try/finally using continue and break
I wrote these tests a while ago while trying to improve the bytecode,
but didn't end up making them pass and gave up. They work in AST
interpreter mode, so we can have them in now to have them around for
anyone who wants to try and make them pass in bytecode.
2022-11-08 21:10:53 +00:00

341 lines
10 KiB
JavaScript

test("Nested try/catch/finally with break", () => {
const executionOrder = [];
try {
for (const i = 1337; ; expect().fail("Jumped to for loop update block")) {
try {
try {
try {
break;
} finally {
expect(i).toBe(1337);
executionOrder.push(1);
}
} finally {
expect(i).toBe(1337);
executionOrder.push(2);
}
} finally {
expect(i).toBe(1337);
executionOrder.push(3);
}
expect().fail("Running code after second to most outer try");
}
} finally {
expect(() => {
i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined");
executionOrder.push(4);
}
expect(() => {
i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined");
expect(executionOrder).toEqual([1, 2, 3, 4]);
});
test("Nested try/finally with labelled break", () => {
const executionOrder = [];
outer: try {
const libjs = 0;
expect(libjs).toBe(0);
try {
const serenity = 1;
expect(libjs).toBe(0);
expect(serenity).toBe(1);
for (const i = 2; ; expect().fail("Jumped to for loop update block")) {
const foo = 3;
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
try {
const bar = 4;
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(bar).toBe(4);
try {
const baz = 5;
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(bar).toBe(4);
expect(baz).toBe(5);
try {
const whf = 6;
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(bar).toBe(4);
expect(baz).toBe(5);
expect(whf).toBe(6);
break outer;
} finally {
const innerFinally1 = 7;
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(bar).toBe(4);
expect(baz).toBe(5);
expect(innerFinally1).toBe(7);
executionOrder.push(1);
}
expect().fail("Running code after most inner try");
} finally {
const innerFinally2 = 8;
expect(() => {
baz;
}).toThrowWithMessage(ReferenceError, "'baz' is not defined");
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(() => {
innerFinally1;
}).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined");
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(bar).toBe(4);
expect(innerFinally2).toBe(8);
executionOrder.push(2);
}
expect().fail("Running code after second to most inner try");
} finally {
const innerFinally3 = 9;
expect(() => {
bar;
}).toThrowWithMessage(ReferenceError, "'bar' is not defined");
expect(() => {
baz;
}).toThrowWithMessage(ReferenceError, "'baz' is not defined");
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(() => {
innerFinally1;
}).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined");
expect(() => {
innerFinally2;
}).toThrowWithMessage(ReferenceError, "'innerFinally2' is not defined");
expect(libjs).toBe(0);
expect(serenity).toBe(1);
expect(i).toBe(2);
expect(foo).toBe(3);
expect(innerFinally3).toBe(9);
executionOrder.push(3);
}
expect().fail("Running code after third to most inner try");
}
expect().fail("Running code after for loop");
} finally {
const innerFinally4 = 10;
expect(() => {
serenity;
}).toThrowWithMessage(ReferenceError, "'serenity' is not defined");
expect(() => {
i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined");
expect(() => {
foo;
}).toThrowWithMessage(ReferenceError, "'foo' is not defined");
expect(() => {
bar;
}).toThrowWithMessage(ReferenceError, "'bar' is not defined");
expect(() => {
baz;
}).toThrowWithMessage(ReferenceError, "'baz' is not defined");
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(() => {
innerFinally1;
}).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined");
expect(() => {
innerFinally2;
}).toThrowWithMessage(ReferenceError, "'innerFinally2' is not defined");
expect(() => {
innerFinally3;
}).toThrowWithMessage(ReferenceError, "'innerFinally3' is not defined");
expect(libjs).toBe(0);
expect(innerFinally4).toBe(10);
executionOrder.push(4);
}
expect().fail("Running code after second to outer try");
} finally {
const innerFinally5 = 11;
expect(() => {
libjs;
}).toThrowWithMessage(ReferenceError, "'libjs' is not defined");
expect(() => {
serenity;
}).toThrowWithMessage(ReferenceError, "'serenity' is not defined");
expect(() => {
i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined");
expect(() => {
foo;
}).toThrowWithMessage(ReferenceError, "'foo' is not defined");
expect(() => {
bar;
}).toThrowWithMessage(ReferenceError, "'bar' is not defined");
expect(() => {
baz;
}).toThrowWithMessage(ReferenceError, "'baz' is not defined");
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(() => {
innerFinally1;
}).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined");
expect(() => {
innerFinally2;
}).toThrowWithMessage(ReferenceError, "'innerFinally2' is not defined");
expect(() => {
innerFinally3;
}).toThrowWithMessage(ReferenceError, "'innerFinally3' is not defined");
expect(() => {
innerFinally4;
}).toThrowWithMessage(ReferenceError, "'innerFinally4' is not defined");
expect(innerFinally5).toBe(11);
executionOrder.push(5);
}
expect(() => {
libjs;
}).toThrowWithMessage(ReferenceError, "'libjs' is not defined");
expect(() => {
serenity;
}).toThrowWithMessage(ReferenceError, "'serenity' is not defined");
expect(() => {
i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined");
expect(() => {
foo;
}).toThrowWithMessage(ReferenceError, "'foo' is not defined");
expect(() => {
bar;
}).toThrowWithMessage(ReferenceError, "'bar' is not defined");
expect(() => {
baz;
}).toThrowWithMessage(ReferenceError, "'baz' is not defined");
expect(() => {
whf;
}).toThrowWithMessage(ReferenceError, "'whf' is not defined");
expect(() => {
innerFinally1;
}).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined");
expect(() => {
innerFinally2;
}).toThrowWithMessage(ReferenceError, "'innerFinally2' is not defined");
expect(() => {
innerFinally3;
}).toThrowWithMessage(ReferenceError, "'innerFinally3' is not defined");
expect(() => {
innerFinally4;
}).toThrowWithMessage(ReferenceError, "'innerFinally4' is not defined");
expect(() => {
innerFinally5;
}).toThrowWithMessage(ReferenceError, "'innerFinally5' is not defined");
expect(executionOrder).toEqual([1, 2, 3, 4, 5]);
});
test("labelled break in finally overrides labelled break in try", () => {
const executionOrder = [];
outer: for (const i = 1; ; expect().fail("Jumped to outer for loop update block")) {
inner: for (const j = 2; ; expect().fail("Jumped to inner for loop update block")) {
try {
executionOrder.push(1);
break inner;
} finally {
executionOrder.push(2);
break outer;
}
expect().fail("Running code after try block");
}
expect().fail("Running code after inner for loop");
}
expect(executionOrder).toEqual([1, 2]);
});