From cfaffc881528cdaf5699d024ba9e6c34f9348dc1 Mon Sep 17 00:00:00 2001 From: Marcelo Lv Cabral Date: Tue, 30 Apr 2024 22:31:07 -0700 Subject: [PATCH] Added unit tests for Try Catch --- test/e2e/Syntax.test.js | 29 +++++++---- test/e2e/resources/try-catch.brs | 30 +++++++---- test/interpreter/TryCatch.test.js | 83 +++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 test/interpreter/TryCatch.test.js diff --git a/test/e2e/Syntax.test.js b/test/e2e/Syntax.test.js index 9a1221f7..c13876f7 100644 --- a/test/e2e/Syntax.test.js +++ b/test/e2e/Syntax.test.js @@ -280,24 +280,33 @@ describe("end to end syntax", () => { test("try-catch.brs", async () => { await execute([resourceFile("try-catch.brs")], outputStreams); expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([ - "[pre_try] a = ", + "[pre_try] a =", " 5", - "[in_try] a = ", + "[in_try] a =", " 10", - "[subFunc] a = ", + "[subFunc] a =", " 10", "[thirdLevel]", + "Error # =", " 6502", - "[in_catch] e = ", + "[in_catch] message = ", "subFunc custom error message!", - "[backtrace] = ", + "[in_catch] customField = ", + "true", + "[backtrace] =", " 8", - "[backtrace] = ", - " 22", - "[backtrace] = ", - " 33", - "[post_try] a = ", + "[backtrace] =", + " 25", + "[backtrace] =", + " 41", + "[post_try] a =", " 10", + "[subFunc] a =", + " 11", + "Error # =", + " 24", + "Error message = ", + `Type Mismatch. Operator "*" can't be applied to "Integer" and "String".`, ]); }); }); diff --git a/test/e2e/resources/try-catch.brs b/test/e2e/resources/try-catch.brs index b639bc8a..b8a772c0 100644 --- a/test/e2e/resources/try-catch.brs +++ b/test/e2e/resources/try-catch.brs @@ -1,34 +1,42 @@ sub main() a = 5 - print "[pre_try] a = " a + print "[pre_try] a =" a try a = a * 2 - print "[in_try] a = " a + print "[in_try] a =" a subFunc(a) catch e - print "[in_catch] e = " e.message + print "[in_catch] message = " e.message + print "[in_catch] customField = " e.customField for each bt in e.backtrace - print "[backtrace] = " bt.line_number + print "[backtrace] =" bt.line_number end for end try - print "[post_try] a = " a + print "[post_try] a =" a + subFunc(a + 1) end sub function subFunc(a) try - print "[subFunc] a = " a - thirdLevel() + print "[subFunc] a =" a + if a = 10 + thirdLevel() + end if a = a * "" ' force a type error catch e - print e.number - e.customField = false - throw e + print "Error # =" e.number + if a = 10 + e.customField = true + throw e + else + print "Error message = " e.message + end if endtry end function sub thirdLevel() print "[thirdLevel]" - throw {message: "subFunc custom error message!", number: 6502, customField: true} + throw {message: "subFunc custom error message!", number: 6502, customField: false} end sub diff --git a/test/interpreter/TryCatch.test.js b/test/interpreter/TryCatch.test.js new file mode 100644 index 00000000..d00f67ec --- /dev/null +++ b/test/interpreter/TryCatch.test.js @@ -0,0 +1,83 @@ +const Expr = require("../../lib/parser/Expression"); +const Stmt = require("../../lib/parser/Statement"); +const { Interpreter } = require("../../lib/interpreter"); +const brs = require("../../lib"); +const { Lexeme } = brs.lexer; +const { Int32, BrsString } = brs.types; +const { createMockStreams, allArgs } = require("../e2e/E2ETests"); +const { token, identifier } = require("../parser/ParserTests"); + +let interpreter, stdout; + +describe("interpreter try-catch blocks", () => { + const printError = new Stmt.Print({ print: token(Lexeme.Print, "print") }, [ + new Expr.Variable(identifier("e")), + ]); + + beforeEach(() => { + const outputStreams = createMockStreams(); + interpreter = new Interpreter(outputStreams); + stdout = outputStreams.stdout; + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("executes the try block when no errors are thrown", () => { + const varAssignment = new Stmt.Assignment( + { equals: token(Lexeme.Equals, "=") }, + identifier("a"), + new Expr.Literal(new Int32(0)) + ); + const trySpy = jest.spyOn(varAssignment, "accept"); + const catchSpy = jest.spyOn(printError, "accept"); + + const statements = [ + new Stmt.TryCatch( + /* try block */ new Stmt.Block([varAssignment]), + /* catch block */ new Stmt.Block([printError]), + /* error binding */ new Expr.Variable(identifier("e")), + { + try: token(Lexeme.Try, "try"), + catch: token(Lexeme.Catch, "catch"), + endtry: token(Lexeme.EndTry, "end try"), + } + ), + ]; + + interpreter.exec(statements); + expect(trySpy).toHaveBeenCalledTimes(1); + expect(catchSpy).not.toHaveBeenCalled(); + }); + + it("executes the catch block when an error is thrown", () => { + const badComparison = new Expr.Binary( + new Expr.Literal(new Int32(2)), + token(Lexeme.Less), + new Expr.Literal(new BrsString("1")) + ); + const trySpy = jest.spyOn(badComparison, "accept"); + const catchSpy = jest.spyOn(printError, "accept"); + + const statements = [ + new Stmt.TryCatch( + /* try block */ new Stmt.Block([badComparison]), + /* catch block */ new Stmt.Block([printError]), + /* error binding */ new Expr.Variable(identifier("e")), + { + try: token(Lexeme.Try, "try"), + catch: token(Lexeme.Catch, "catch"), + endtry: token(Lexeme.EndTry, "end try"), + } + ), + ]; + + interpreter.exec(statements); + expect(trySpy).toHaveBeenCalledTimes(1); + expect(catchSpy).toHaveBeenCalledTimes(1); + const output = allArgs(stdout.write).filter((arg) => arg !== "\n"); + expect(output[0]).toMatch(/Type Mismatch./); + }); +});