From 08750f69e4c720e85d73af22f2f938f091fe818e Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Tue, 8 Nov 2022 20:57:36 +0000 Subject: [PATCH] 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. --- .../LibJS/Tests/try-finally-break.js | 341 +++++++++ .../LibJS/Tests/try-finally-continue.js | 679 ++++++++++++++++++ 2 files changed, 1020 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/try-finally-break.js create mode 100644 Userland/Libraries/LibJS/Tests/try-finally-continue.js diff --git a/Userland/Libraries/LibJS/Tests/try-finally-break.js b/Userland/Libraries/LibJS/Tests/try-finally-break.js new file mode 100644 index 00000000000..bcceb4044ce --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/try-finally-break.js @@ -0,0 +1,341 @@ +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]); +}); diff --git a/Userland/Libraries/LibJS/Tests/try-finally-continue.js b/Userland/Libraries/LibJS/Tests/try-finally-continue.js new file mode 100644 index 00000000000..4017cc7d9b6 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/try-finally-continue.js @@ -0,0 +1,679 @@ +test("Nested try/catch/finally with continue", () => { + const executionOrder = []; + + function callFromUpdateBlock(i) { + expect(i).toBe(2); + executionOrder.push(4); + } + + function callFromTestBlock(i) { + expect(i).toBe(2); + executionOrder.push(5); + return false; + } + + try { + const foo = 0; + + expect(foo).toBe(0); + + for (let i = 1; i >= 2 ? callFromTestBlock(i) : true; ++i, callFromUpdateBlock(i)) { + const bar = 2; + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + + try { + const baz = 3; + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + + try { + const serenity = 4; + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(serenity).toBe(4); + + try { + const whf = 5; + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(serenity).toBe(4); + expect(whf).toBe(5); + + continue; + } finally { + const innerFinally1 = 6; + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(serenity).toBe(4); + expect(innerFinally1).toBe(6); + + executionOrder.push(1); + } + + expect().fail("Running code after most inner try in for loop"); + } finally { + const innerFinally2 = 7; + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' is not defined"); + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + innerFinally1; + }).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined"); + + expect(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(innerFinally2).toBe(7); + + executionOrder.push(2); + } + + expect().fail("Running code from after the middle try in for loop"); + } finally { + const innerFinally3 = 8; + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' 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(foo).toBe(0); + expect(i).toBe(1); + expect(bar).toBe(2); + expect(innerFinally3).toBe(8); + + executionOrder.push(3); + } + + expect().fail("Running code from after the outer try in for loop"); + } + + executionOrder.push(6); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' 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(foo).toBe(0); + } finally { + const innerFinally4 = 9; + + expect(() => { + foo; + }).toThrowWithMessage(ReferenceError, "'foo' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' 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).toBe(9); + + executionOrder.push(7); + } + + expect(() => { + foo; + }).toThrowWithMessage(ReferenceError, "'foo' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' 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(executionOrder).toEqual([1, 2, 3, 4, 5, 6, 7]); +}); + +test("Nested try/catch/finally with labelled continue", () => { + const executionOrder = []; + + function callFromUpdateBlock(j) { + expect(j).toBe(2); + executionOrder.push(5); + } + + function callFromTestBlock(j) { + expect(j).toBe(2); + executionOrder.push(6); + return false; + } + + try { + const foo = 0; + + expect(foo).toBe(0); + + outer: for (let j = 1; j >= 2 ? callFromTestBlock(j) : true; ++j, callFromUpdateBlock(j)) { + const bar = 2; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + + try { + const baz = 3; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + + for (const i = 4; ; expect().fail("Jumped to inner for loop update block")) { + const serenity = 5; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + + try { + const whf = 6; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(whf).toBe(6); + + try { + const beforeContinueTry = 7; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(whf).toBe(6); + expect(beforeContinueTry).toBe(7); + + try { + const continueTry = 8; + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(whf).toBe(6); + expect(beforeContinueTry).toBe(7); + expect(continueTry).toBe(8); + + continue outer; + } finally { + const innerFinally1 = 9; + + expect(() => { + continueTry; + }).toThrowWithMessage( + ReferenceError, + "'continueTry' is not defined" + ); + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(whf).toBe(6); + expect(beforeContinueTry).toBe(7); + expect(innerFinally1).toBe(9); + + executionOrder.push(1); + } + + expect().fail("Running code after most inner try"); + } finally { + const innerFinally2 = 10; + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage( + ReferenceError, + "'beforeContinueTry' is not defined" + ); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' is not defined"); + + expect(() => { + innerFinally1; + }).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined"); + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(whf).toBe(6); + expect(innerFinally2).toBe(10); + + executionOrder.push(2); + } + + expect().fail("Running code after second to most inner try"); + } finally { + const innerFinally3 = 11; + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage(ReferenceError, "'beforeContinueTry' is not defined"); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' is not defined"); + + expect(() => { + innerFinally1; + }).toThrowWithMessage(ReferenceError, "'innerFinally1' is not defined"); + + expect(() => { + innerFinally2; + }).toThrowWithMessage(ReferenceError, "'innerFinally2' is not defined"); + + expect(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(baz).toBe(3); + expect(i).toBe(4); + expect(serenity).toBe(5); + expect(innerFinally3).toBe(11); + + executionOrder.push(3); + } + + expect().fail("Running code after third to most inner try"); + } + + expect().fail("Running code after inner for loop"); + } finally { + const innerFinally4 = 12; + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' is not defined"); + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage(ReferenceError, "'beforeContinueTry' is not defined"); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' 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(foo).toBe(0); + expect(j).toBe(1); + expect(bar).toBe(2); + expect(innerFinally4).toBe(12); + + executionOrder.push(4); + } + + expect().fail("Running code after try in outer for loop"); + } + + expect(() => { + j; + }).toThrowWithMessage(ReferenceError, "'j' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' is not defined"); + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage(ReferenceError, "'beforeContinueTry' is not defined"); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' 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(foo).toBe(0); + + executionOrder.push(7); + } finally { + const innerFinally5 = 13; + + expect(() => { + foo; + }).toThrowWithMessage(ReferenceError, "'foo' is not defined"); + + expect(() => { + j; + }).toThrowWithMessage(ReferenceError, "'j' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' is not defined"); + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage(ReferenceError, "'beforeContinueTry' is not defined"); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' 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(13); + + executionOrder.push(8); + } + + expect(() => { + foo; + }).toThrowWithMessage(ReferenceError, "'foo' is not defined"); + + expect(() => { + j; + }).toThrowWithMessage(ReferenceError, "'j' is not defined"); + + expect(() => { + bar; + }).toThrowWithMessage(ReferenceError, "'bar' is not defined"); + + expect(() => { + baz; + }).toThrowWithMessage(ReferenceError, "'baz' is not defined"); + + expect(() => { + i; + }).toThrowWithMessage(ReferenceError, "'i' is not defined"); + + expect(() => { + serenity; + }).toThrowWithMessage(ReferenceError, "'serenity' is not defined"); + + expect(() => { + whf; + }).toThrowWithMessage(ReferenceError, "'whf' is not defined"); + + expect(() => { + beforeContinueTry; + }).toThrowWithMessage(ReferenceError, "'beforeContinueTry' is not defined"); + + expect(() => { + continueTry; + }).toThrowWithMessage(ReferenceError, "'continueTry' 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, 6, 7, 8]); +}); + +test("labelled continue in finally overrides labelled continue in try", () => { + const executionOrder = []; + + function callFromUpdateBlock(i) { + expect(i).toBe(2); + executionOrder.push(3); + } + + function callFromTestBlock(i) { + expect(i).toBe(2); + executionOrder.push(4); + return false; + } + + outer: for (let i = 1; i >= 2 ? callFromTestBlock(i) : true; ++i, callFromUpdateBlock(i)) { + inner: for (const j = 2; ; expect().fail("Jumped to inner for loop update block")) { + try { + executionOrder.push(1); + continue inner; + } finally { + executionOrder.push(2); + continue outer; + } + + expect().fail("Running code after try block"); + } + + expect().fail("Running code after inner for loop"); + } + + expect(executionOrder).toEqual([1, 2, 3, 4]); +});