// SPDX-FileCopyrightText: 2022 Johannes Loher // // SPDX-License-Identifier: MIT import { describe, expect, it } from "vitest"; import { literals, safeOperators } from "../../src/expression-evaluation/grammar"; import { Validator } from "../../src/expression-evaluation/validator"; describe("Validator", () => { it("allows identifier according to the given predicate", () => { // given const predicate = (identifier: string) => identifier === "true"; const validator = new Validator(predicate); const input = "true"; // when const validate = () => validator.validate(input); // then expect(validate).not.toThrow(); }); it("disallows identifier according to the given predicate", () => { // given const predicate = (identifier: string) => identifier === "false"; const validator = new Validator(predicate); const input = "true"; // when const validate = () => validator.validate(input); // then expect(validate).toThrowError("'true' is not an allowed identifier"); }); it("allows multiple identifiers according to the given predicate", () => { // given const predicate = (identifier: string) => identifier === "true" || identifier === "null"; const validator = new Validator(predicate); const input = "true null"; // when const validate = () => validator.validate(input); // then expect(validate).not.toThrow(); }); it("allows multiple identifiers in a more complex expression according to the given rule", () => { // given const predicate = (identifier: string) => identifier === "true" || identifier === "null"; const validator = new Validator(predicate); const input = "true === null"; // when const validate = () => validator.validate(input); // then expect(validate).not.toThrow(); }); it("mentions the first not allowed identifier in the thrown errror", () => { // given const predicate = (identifier: string) => identifier === "true" || identifier === "null"; const validator = new Validator(predicate); const input = "true === null && undefined === false"; // when const validate = () => validator.validate(input); // then expect(validate).toThrowError("'undefined' is not an allowed identifier."); }); it("disallows invalid invalid tokens", () => { // given const validator = new Validator(); const input = ";"; // when const validate = () => validator.validate(input); // then expect(validate).toThrowError("Invalid or unexpected token (0)"); }); it("allows a complicated valid expression", () => { // given const predicate = (identifier: string) => [...safeOperators, ...literals, "floor", "random"].includes(identifier); const validator = new Validator(predicate); const input = "typeof (floor(random() * 5) / 2) === 'number' ? 42 : 'foo'"; // when const validate = () => validator.validate(input); // then expect(validate).not.toThrow(); }); it("disallows a complicated expression if it contains a disallowed identifier", () => { // given const predicate = (identifier: string) => [...safeOperators, ...literals, "ceil"].includes(identifier); const validator = new Validator(predicate); const input = "ceil.constructor('alert(1); return 1;')()"; // when const validate = () => validator.validate(input); // then expect(validate).toThrowError("'constructor' is not an allowed identifier."); }); it("disallows arrow functions", () => { // given const validator = new Validator(); const input = "() => {}"; // when const validate = () => validator.validate(input); // then expect(validate).toThrowError("Invalid or unexpected token (3)"); }); });