diff --git a/common/package-lock.json b/common/package-lock.json index ee15bf5..5df6794 100644 --- a/common/package-lock.json +++ b/common/package-lock.json @@ -13,6 +13,7 @@ "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-node-resolve": "^15.3.0", + "@types/chai-as-promised": "^8.0.1", "c8": "^10.1.2", "rollup": "^4.22.4", "rollup-plugin-cleanup": "^3.2.1" @@ -2198,9 +2199,17 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.0.tgz", "integrity": "sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA==", - "dev": true, "license": "MIT" }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, "node_modules/@types/chai-spies": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/chai-spies/-/chai-spies-1.0.6.tgz", diff --git a/common/package.json b/common/package.json index e85d3ff..a368ef5 100644 --- a/common/package.json +++ b/common/package.json @@ -25,6 +25,7 @@ "devDependencies": { "@types/chai": "^5.0.0", "@types/chai-spies": "^1.0.6", + "@types/chai-as-promised": "^8.0.1", "@types/mocha": "^10.0.8", "chai": "^5.1.1", "chai-as-promised": "^8.0.0", diff --git a/common/src/module/latex.mjs b/common/src/module/latex.mjs index 830f096..dca9422 100644 --- a/common/src/module/latex.mjs +++ b/common/src/module/latex.mjs @@ -62,7 +62,7 @@ class LatexRenderResult { class LatexAPI extends Module { /** @type {LatexInterface} */ #latex = null - + constructor() { super("Latex", { latex: LatexInterface, @@ -142,9 +142,10 @@ class LatexAPI extends Module { */ parif(elem, contents) { elem = elem.toString() - if(elem[0] !== "(" && elem.at(-1) !== ")" && contents.some(x => elem.indexOf(x) > 0)) + const contains = contents.some(x => elem.indexOf(x) > 0) + if(elem[0] !== "(" && elem.at(-1) !== ")" && contains) return this.par(elem) - if(elem[0] === "(" && elem.at(-1) === ")") + if(elem[0] === "(" && elem.at(-1) === ")" && !contains) return elem.removeEnclosure() return elem } diff --git a/common/test/hooks.mjs b/common/test/hooks.mjs index abe468f..66e9da9 100644 --- a/common/test/hooks.mjs +++ b/common/test/hooks.mjs @@ -22,8 +22,10 @@ import { MockLatex } from "./mock/latex.mjs" import { use } from "chai" import spies from "chai-spies" +import promised from "chai-as-promised" function setup() { + use(promised) const { spy } = use(spies) globalThis.Helper = new MockHelper() diff --git a/common/test/mock/helper.mjs b/common/test/mock/helper.mjs index c2b024f..4cab472 100644 --- a/common/test/mock/helper.mjs +++ b/common/test/mock/helper.mjs @@ -22,7 +22,8 @@ const DEFAULT_SETTINGS = { "check_for_updates": true, "reset_redo_stack": true, "last_install_greet": "0", - "enable_latex": false, + "enable_latex": true, + "enable_latex_async": true, "expression_editor": { "autoclose": true, "colorize": true, diff --git a/common/test/mock/latex.mjs b/common/test/mock/latex.mjs index c0a029c..2d6fb5f 100644 --- a/common/test/mock/latex.mjs +++ b/common/test/mock/latex.mjs @@ -22,10 +22,7 @@ const PIXEL = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAA export class MockLatex { constructor() { - } - - get supportsAsyncRender() { - return true + this.supportsAsyncRender = true } /** diff --git a/common/test/module/latex.mjs b/common/test/module/latex.mjs new file mode 100644 index 0000000..13ffd03 --- /dev/null +++ b/common/test/module/latex.mjs @@ -0,0 +1,144 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2021-2024 Ad5001 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Load prior tests +import "./base.mjs" +import "./expreval.mjs" + +import { describe, it } from "mocha" +import { expect } from "chai" +import { existsSync } from "../mock/fs.mjs" + +const { spy } = chaiPlugins + +import LatexAPI from "../../src/module/latex.mjs" + +describe("Module/Latex", function() { + it("is defined as a global", function() { + expect(globalThis.Modules.Latex).to.equal(LatexAPI) + }) + + describe("#initialize", function() { + it("isn't enabled before initialization", function() { + expect(LatexAPI.enabled).to.be.false + }) + + it("is enabled after initialization", function() { + LatexAPI.initialize({ latex: Latex, helper: Helper }) + expect(LatexAPI.enabled).to.equal(Helper.getSetting("enable_latex")) + expect(LatexAPI.initialized).to.be.true + }) + }) + + describe("#requestAsyncRender", function() { + it("should return a render result with a valid source, a width, and a height", async function() { + const data = await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") + expect(data).to.be.an("object") + expect(data.source).to.be.a("string") + expect(data.source).to.satisfy(existsSync) + expect(data.height).to.be.a("number") + expect(data.width).to.be.a("number") + }) + + it("should call functions from the LaTeX module", async function() { + const renderSyncSpy = spy.on(Latex, "renderSync") + const renderAsyncSpy = spy.on(Latex, "renderAsync") + Latex.supportsAsyncRender = true + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") + expect(renderAsyncSpy).to.have.been.called.once + expect(renderSyncSpy).to.have.been.called.once // Called async + Latex.supportsAsyncRender = false + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") + expect(renderAsyncSpy).to.have.been.called.once // From the time before + expect(renderSyncSpy).to.have.been.called.twice + Latex.supportsAsyncRender = true + }) + + it("should not reply with the same source for different markup, font size, or color.", async function() { + const datas = [ + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033"), + await LatexAPI.requestAsyncRender("\\frac{x}{4}", 13, "#AA0033"), + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 14, "#AA0033"), + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#0033AA") + ] + const sources = datas.map(x => x.source) + expect(new Set(sources)).to.have.a.lengthOf(4) + }) + }) + + describe("#findPrerendered", function() { + it("should return the same data as async render for the same markup, font size, and color", async function() { + const data = await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") + const found = LatexAPI.findPrerendered("\\frac{x}{3}", 13, "#AA0033") + expect(found).to.not.be.null + expect(found.source).to.equal(data.source) + expect(found.width).to.equal(data.width) + }) + + it("should return null if the markup hasn't been prerendered with the same markup, font size, and color", async function() { + await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") + expect(LatexAPI.findPrerendered("\\frac{y}{3}", 13, "#AA0033")).to.be.null + expect(LatexAPI.findPrerendered("\\frac{x}{3}", 12, "#AA0033")).to.be.null + expect(LatexAPI.findPrerendered("\\frac{x}{3}", 13, "#3300AA")).to.be.null + }) + }) + + describe("#par", function() { + it("should add parentheses to strings", function() { + expect(LatexAPI.par("string")).to.equal("(string)") + expect(LatexAPI.par("aaaa")).to.equal("(aaaa)") + expect(LatexAPI.par("")).to.equal("()") + expect(LatexAPI.par("(example)")).to.equal("((example))") + }) + }) + + describe("#parif", function() { + it("should add parentheses to strings that contain one of the ones in the list", function() { + expect(LatexAPI.parif("string", ["+"])).to.equal("string") + expect(LatexAPI.parif("string+assert", ["+"])).to.equal("(string+assert)") + expect(LatexAPI.parif("string+assert", ["+", "-"])).to.equal("(string+assert)") + expect(LatexAPI.parif("string-assert", ["+", "-"])).to.equal("(string-assert)") + }) + + it("shouldn't add new parentheses to strings that contains one of the ones in the list if they already have one", function() { + expect(LatexAPI.parif("(string+assert", ["+"])).to.equal("((string+assert)") + expect(LatexAPI.parif("string+assert)", ["+"])).to.equal("(string+assert))") + expect(LatexAPI.parif("(string+assert)", ["+"])).to.equal("(string+assert)") + expect(LatexAPI.parif("(string+assert)", ["+", "-"])).to.equal("(string+assert)") + expect(LatexAPI.parif("(string-assert)", ["+", "-"])).to.equal("(string-assert)") + }) + + it("shouldn't add parentheses to strings that does not contains one of the ones in the list", function() { + expect(LatexAPI.parif("string", ["+"])).to.equal("string") + expect(LatexAPI.parif("string+assert", ["-"])).to.equal("string+assert)") + expect(LatexAPI.parif("(string*assert", ["+", "-"])).to.equal("(string*assert") + expect(LatexAPI.parif("string/assert)", ["+", "-"])).to.equal("string/assert)") + }) + + it("should remove parentheses from strings that does not contains one of the ones in the list", function() { + expect(LatexAPI.parif("(string)", ["+"])).to.equal("string") + expect(LatexAPI.parif("(string+assert)", ["-"])).to.equal("string+assert") + expect(LatexAPI.parif("((string*assert)", ["+", "-"])).to.equal("(string*assert") + expect(LatexAPI.parif("(string/assert))", ["+", "-"])).to.equal("string/assert)") + }) + }) + + describe("#variable", function() { + + }) +}) \ No newline at end of file