import { AsText, TextPiece } from "../words"; import { Expr } from "./expr"; describe("expr", () => { describe("does math", () => { test.each([ ["1", "1"], ["-1", "-1"], ["1 + 2", "3"], ["1 - 2", "-1"], ["1 * 2", "2"], ["1 / 2", "0.5"], // floored division ["1 // 5", "0"], ["6 // 5", "1"], ["-1 // 5", "-1"], ["-6 // 5", "-2"], ["1 // -5", "-1"], ["6 // -5", "-2"], ["-1 // -5", "0"], ["-6 // -5", "1"], // floored modulo ["1 % 5", "1"], ["6 % 5", "1"], ["-6 % 5", "4"], ["-1 % 5", "4"], ["1 % -5", "-4"], ["6 % -5", "-4"], ["-6 % -5", "-1"], ["-1 % -5", "-1"], ])("%s", (expression, result) => { const actualResult = Expr({}, [{ text: expression }]); expect("error" in actualResult).toBeFalsy(); expect(AsText(actualResult as TextPiece)).toEqual(result); }); }); describe("handles operator precedence", () => { test.each([ ["1 - 2 + 1", "0"], ["1 + 2 * 3", "7"], ["1 / 2 + 3", "3.5"], ])("%s", (expression, result) => { const actualResult = Expr({}, [{ text: expression }]); expect("error" in actualResult).toBeFalsy(); expect(AsText(actualResult as TextPiece)).toEqual(result); }); }); // TODO: parentheses // TODO; error reporting describe("rejects invalid expressions", () => { test.each([[""], ["1 $ 2"], ["1 1 + 2"], ["1 + + 2"], ["$ 1"]])( "%s", (expression) => { const actualResult = Expr({}, [{ text: expression }]); expect("error" in actualResult).toBeTruthy(); } ); }); // TODO: operators should only be accepted as bare words describe("ignores an expr prefix", () => { test.each([ [["1", "+", "2"]], [["expr", "1", "+", "2"]], [["1 + 2"]], [["expr", "1 + 2"]], ])("%s", (argv) => { const actualResult = Expr( {}, argv.map((text) => ({ bare: text })) ); expect("error" in actualResult).toBeFalsy(); expect(AsText(actualResult as TextPiece)).toEqual("3"); }); }); });