diff --git a/common/src/events.mjs b/common/src/events.mjs index 702fc7d..25f5bf3 100644 --- a/common/src/events.mjs +++ b/common/src/events.mjs @@ -23,11 +23,17 @@ export class BaseEvent { + #name + /** * @property {string} name - Name of the event. */ constructor(name) { - this.name = name + this.#name = name + } + + get name() { + return this.#name } } diff --git a/common/src/module/objects.mjs b/common/src/module/objects.mjs index a95dc89..23801be 100644 --- a/common/src/module/objects.mjs +++ b/common/src/module/objects.mjs @@ -24,6 +24,10 @@ class ObjectsAPI extends Module { constructor() { super("Objects") + /** + * List of object constructors. + * @type {Object.} + */ this.types = {} /** * List of objects for each type of object. @@ -65,7 +69,7 @@ class ObjectsAPI extends Module { * @param {string} newName - Name to rename the object to. */ renameObject(oldName, newName) { - let obj = this.currentObjectsByName[oldName] + const obj = this.currentObjectsByName[oldName] delete this.currentObjectsByName[oldName] this.currentObjectsByName[newName] = obj obj.name = newName @@ -76,7 +80,7 @@ class ObjectsAPI extends Module { * @param {string} objName - Current name of the object. */ deleteObject(objName) { - let obj = this.currentObjectsByName[objName] + const obj = this.currentObjectsByName[objName] if(obj !== undefined) { this.currentObjects[obj.type].splice(this.currentObjects[obj.type].indexOf(obj), 1) obj.delete() diff --git a/common/src/module/settings.mjs b/common/src/module/settings.mjs index e6313c7..64c39c2 100644 --- a/common/src/module/settings.mjs +++ b/common/src/module/settings.mjs @@ -49,7 +49,8 @@ class SettingsAPI extends Module { static emits = ["changed"] #nonConfigurable = ["saveFilename"] - + + /** @type {Map} */ #properties = new Map([ ["saveFilename", ""], ["xzoom", 100], @@ -105,9 +106,8 @@ class SettingsAPI extends Module { * @param {boolean} byUser - Set to true if the user is at the origin of this change. */ set(property, value, byUser) { - if(!this.#properties.has(property)) { + if(!this.#properties.has(property)) throw new Error(`Property ${property} is not a setting.`) - } const oldValue = this.#properties.get(property) const propType = typeof oldValue if(byUser) diff --git a/common/test/basics/events.mjs b/common/test/basics/events.mjs index 8261ff1..092f037 100644 --- a/common/test/basics/events.mjs +++ b/common/test/basics/events.mjs @@ -16,15 +16,12 @@ * along with this program. If not, see . */ -import { BaseEventEmitter, BaseEvent } from "../../src/events.mjs" - import { describe, it } from "mocha" -import { expect, use } from "chai" -import spies from "chai-spies" +import { expect } from "chai" -// Setting up modules -const { spy } = use(spies) +const { spy } = chaiPlugins +import { BaseEventEmitter, BaseEvent } from "../../src/events.mjs" class MockEmitter extends BaseEventEmitter { static emits = ["example1", "example2"] @@ -43,12 +40,11 @@ class MockEvent2 extends BaseEvent { } } -const sandbox = spy.sandbox() - describe("Lib/EventsEmitters", function() { - - afterEach(() => { - sandbox.restore() + it("sends events with unique and readonly names", function() { + const event = new MockEvent1() + expect(event.name).to.equal("example1") + expect(() => event.name = "not").to.throw() }) it("forwards events to all of its listeners", function() { @@ -71,8 +67,8 @@ describe("Lib/EventsEmitters", function() { emitter.emit(mockEvent1) emitter.emit(mockEvent2) expect(listener).to.have.been.called.twice - expect(listener).to.also.have.been.called.with.exactly(mockEvent1) - expect(listener).to.also.have.been.called.with.exactly(mockEvent2) + expect(listener).to.have.been.first.called.with.exactly(mockEvent1) + expect(listener).to.have.been.second.called.with.exactly(mockEvent2) }) it("is able to have listeners removed", function() { diff --git a/common/test/basics/module.mjs b/common/test/basics/module-base.mjs similarity index 98% rename from common/test/basics/module.mjs rename to common/test/basics/module-base.mjs index 5093096..9a38109 100644 --- a/common/test/basics/module.mjs +++ b/common/test/basics/module-base.mjs @@ -16,15 +16,15 @@ * along with this program. If not, see . */ -// Load prior events +// Load prior tests import "./events.mjs" import "./interface.mjs" import { describe, it } from "mocha" import { expect } from "chai" +import { MockDialog } from "../mock/dialog.mjs" import { BOOLEAN, DialogInterface, FUNCTION, NUMBER, STRING } from "../../src/module/interface.mjs" import { Module } from "../../src/module/common.mjs" -import { MockDialog } from "../mock/dialog.mjs" class MockModule extends Module { constructor() { @@ -38,7 +38,7 @@ class MockModule extends Module { } } -describe("Modules/Base", function() { +describe("Module/Base", function() { it("defined a Modules global", function() { expect(globalThis.Modules).to.not.be.undefined }) diff --git a/common/test/basics/module-objects.mjs b/common/test/basics/module-objects.mjs new file mode 100644 index 0000000..ffc8076 --- /dev/null +++ b/common/test/basics/module-objects.mjs @@ -0,0 +1,30 @@ +/** + * 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 "./module-base.mjs" +import "./utils.mjs" + +import { describe, it } from "mocha" +import { expect } from "chai" + +import Objects from "../../src/module/objects.mjs" + +describe("Module/Objects", function() { + +}) \ No newline at end of file diff --git a/common/test/basics/module-settings.mjs b/common/test/basics/module-settings.mjs new file mode 100644 index 0000000..ea26556 --- /dev/null +++ b/common/test/basics/module-settings.mjs @@ -0,0 +1,101 @@ +/** + * 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 "./module-base.mjs" +import "./utils.mjs" + +import { describe, it } from "mocha" +import { expect } from "chai" + +const { spy } = chaiPlugins + +import Settings from "../../src/module/settings.mjs" +import { BaseEvent } from "../../src/events.mjs" + +describe("Module/Settings", function() { + it("is defined as a global", function() { + expect(globalThis.Modules.Settings).to.equal(Settings) + }) + + it("has base defined properties even before initialization", function() { + expect(Settings.saveFilename).to.be.a("string") + expect(Settings.xzoom).to.be.a("number") + expect(Settings.yzoom).to.be.a("number") + expect(Settings.xmin).to.be.a("number") + expect(Settings.ymax).to.be.a("number") + expect(Settings.xaxisstep).to.be.a("string") + expect(Settings.yaxisstep).to.be.a("string") + expect(Settings.xlabel).to.be.a("string") + expect(Settings.ylabel).to.be.a("string") + expect(Settings.linewidth).to.be.a("number") + expect(Settings.textsize).to.be.a("number") + expect(Settings.logscalex).to.be.a("boolean") + expect(Settings.showxgrad).to.be.a("boolean") + expect(Settings.showygrad).to.be.a("boolean") + }) + + it("can be set values, but only of the right type", function() { + expect(() => Settings.set("xzoom", "", false)).to.throw() + expect(() => Settings.set("xlabel", true, false)).to.throw() + expect(() => Settings.set("showxgrad", 2, false)).to.throw() + + expect(() => Settings.set("xzoom", 200, false)).to.not.throw() + expect(() => Settings.set("xlabel", "x", false)).to.not.throw() + expect(() => Settings.set("showxgrad", false, false)).to.not.throw() + }) + + it("cannot be set unknown settings", function() { + expect(() => Settings.set("unknown", "", false)).to.throw() + }) + + it("sends an event when a value is set", function() { + const listener = spy((e) => { + expect(e).to.be.an.instanceof(BaseEvent) + expect(e.name).to.equal("changed") + expect(e.property).to.equal("xzoom") + expect(e.newValue).to.equal(300) + expect(e.byUser).to.be.true + }) + Settings.on("changed", listener) + Settings.set("xzoom", 300, true) + expect(listener).to.have.been.called.once + Settings.off("changed", listener) + }) + + it("requires a helper to set default values", function() { + spy.on(Settings, "set") + expect(() => Settings.initialize({})).to.throw() + expect(() => Settings.initialize({ helper: globalThis.Helper })).to.not.throw() + expect(Settings.set).to.have.been.called.exactly(13) + expect(Settings.set).to.not.have.been.called.with("saveFilename") + expect(Settings.set).to.have.been.called.with("xzoom") + expect(Settings.set).to.have.been.called.with("yzoom") + expect(Settings.set).to.have.been.called.with("xmin") + expect(Settings.set).to.have.been.called.with("ymax") + expect(Settings.set).to.have.been.called.with("xaxisstep") + expect(Settings.set).to.have.been.called.with("yaxisstep") + expect(Settings.set).to.have.been.called.with("xlabel") + expect(Settings.set).to.have.been.called.with("ylabel") + expect(Settings.set).to.have.been.called.with("linewidth") + expect(Settings.set).to.have.been.called.with("textsize") + expect(Settings.set).to.have.been.called.with("logscalex") + expect(Settings.set).to.have.been.called.with("showxgrad") + expect(Settings.set).to.have.been.called.with("showygrad") + }) +}) \ No newline at end of file diff --git a/common/test/hooks.mjs b/common/test/hooks.mjs index 0f3ebda..abe468f 100644 --- a/common/test/hooks.mjs +++ b/common/test/hooks.mjs @@ -15,14 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -import * as fs from "./mock/fs.mjs"; -import Qt from "./mock/qt.mjs"; -import { MockHelper } from "./mock/helper.mjs"; -import { MockLatex } from "./mock/latex.mjs"; +import * as fs from "./mock/fs.mjs" +import Qt from "./mock/qt.mjs" +import { MockHelper } from "./mock/helper.mjs" +import { MockLatex } from "./mock/latex.mjs" + +import { use } from "chai" +import spies from "chai-spies" function setup() { + const { spy } = use(spies) + globalThis.Helper = new MockHelper() globalThis.Latex = new MockLatex() + globalThis.chaiPlugins = { spy } } setup()