125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
// 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)");
|
|
});
|
|
});
|