Files
plainleaf/plugs/configuration-manager/lua.test.ts
T
Zef Hemel 74173af525 Configuration Manager: Libraries tab
Add a Libraries tab to the configuration manager covering installed libraries, installable libraries (from repositories),  repositories themselves, and detection of "rogue" plugs installed outside a library.

Rename the managed-block marker from "configuration-ui" to"configuration-manager" to match the plug name.
2026-04-21 16:56:55 +02:00

196 lines
6.2 KiB
TypeScript

import { describe, expect, test } from "vitest";
import { parseLuaLiteral, parseManagedBlock, toLua, toLuaKey } from "./lua.ts";
describe("toLua", () => {
test("booleans", () => {
expect(toLua(true)).toBe("true");
expect(toLua(false)).toBe("false");
});
test("numbers", () => {
expect(toLua(42)).toBe("42");
expect(toLua(3.14)).toBe("3.14");
expect(toLua(-1)).toBe("-1");
expect(toLua(0)).toBe("0");
});
test("simple strings", () => {
expect(toLua("hello")).toBe('"hello"');
expect(toLua("")).toBe('""');
});
test("strings with special characters", () => {
expect(toLua('say "hi"')).toBe('"say \\"hi\\""');
expect(toLua("back\\slash")).toBe('"back\\\\slash"');
expect(toLua("line\nbreak")).toBe('"line\\nbreak"');
expect(toLua("tab\there")).toBe('"tab\\there"');
});
test("flat object", () => {
expect(toLua({ enabled: true, name: "test" })).toBe(
'{\n enabled = true,\n name = "test",\n}',
);
});
test("nested object", () => {
const val = { smartQuotes: { enabled: true, double: { left: "\u201c" } } };
const result = toLua(val);
expect(result).toContain("smartQuotes = {");
expect(result).toContain("enabled = true");
expect(result).toContain("double = {");
});
test("empty object", () => {
expect(toLua({})).toBe("{}");
});
test("array", () => {
expect(toLua(["a", "b"])).toBe('{\n "a",\n "b",\n}');
});
test("null and undefined are skipped in objects", () => {
expect(toLua({ a: 1, b: null, c: undefined })).toBe("{\n a = 1,\n}");
});
});
describe("toLuaKey", () => {
test("simple identifiers", () => {
expect(toLuaKey("name")).toBe("name");
expect(toLuaKey("enabled")).toBe("enabled");
});
test("keys needing brackets", () => {
expect(toLuaKey("my-key")).toBe('["my-key"]');
expect(toLuaKey("123")).toBe('["123"]');
expect(toLuaKey("has space")).toBe('["has space"]');
});
});
describe("parseLuaLiteral", () => {
test("scalars", () => {
expect(parseLuaLiteral("true")).toBe(true);
expect(parseLuaLiteral("false")).toBe(false);
expect(parseLuaLiteral("nil")).toBe(undefined);
expect(parseLuaLiteral("42")).toBe(42);
expect(parseLuaLiteral("-3.14")).toBe(-3.14);
expect(parseLuaLiteral('"hello"')).toBe("hello");
expect(parseLuaLiteral('""')).toBe("");
});
test("returns undefined for unsupported shapes", () => {
expect(parseLuaLiteral("{}")).toBe(undefined);
expect(parseLuaLiteral('"has \\"quote\\""')).toBe(undefined);
});
test("ignores surrounding whitespace", () => {
expect(parseLuaLiteral(" true ")).toBe(true);
expect(parseLuaLiteral(' "x" ')).toBe("x");
});
});
describe("toLua / parseLuaLiteral round-trip (supported scalars)", () => {
// Only round-trips scalars: parseLuaLiteral does not parse tables.
const cases: unknown[] = [
true,
false,
undefined,
0,
42,
-1,
3.14,
"",
"hello",
"with spaces",
];
for (const value of cases) {
test(`${JSON.stringify(value) ?? "undefined"}`, () => {
expect(parseLuaLiteral(toLua(value))).toBe(value);
});
}
});
describe("parseManagedBlock", () => {
test("parses config.set lines", () => {
const block = `-- managed-by: configuration-manager
config.set("shortWikiLinks", false)
config.set("smartQuotes.enabled", true)
config.set("autoCloseBrackets", "([{")`;
const { configOverrides, commandOverrides } = parseManagedBlock(block);
expect(configOverrides).toEqual({
shortWikiLinks: false,
"smartQuotes.enabled": true,
autoCloseBrackets: "([{",
});
expect(commandOverrides).toEqual({});
});
test("parses command.update lines", () => {
const block = `command.update { name = "Some: Command", key = "Ctrl-x", mac = "Cmd-x" }
command.update { name = "Other", key = "Ctrl-y" }`;
const { commandOverrides } = parseManagedBlock(block);
expect(commandOverrides).toEqual({
"Some: Command": { key: "Ctrl-x", mac: "Cmd-x" },
"Other": { key: "Ctrl-y" },
});
});
test("parses multi-stroke chord bindings", () => {
const block =
`command.update { name = "Save All", key = "Ctrl-x Ctrl-s", mac = "Cmd-x Cmd-s" }`;
const { commandOverrides } = parseManagedBlock(block);
expect(commandOverrides).toEqual({
"Save All": { key: "Ctrl-x Ctrl-s", mac: "Cmd-x Cmd-s" },
});
});
test("parses array bindings", () => {
const block =
`command.update { name = "Search", key = { "Ctrl-f", "Mod-s" }, mac = { "Cmd-f" } }`;
const { commandOverrides } = parseManagedBlock(block);
expect(commandOverrides).toEqual({
"Search": { key: ["Ctrl-f", "Mod-s"], mac: ["Cmd-f"] },
});
});
test("parses mixed scalar and array fields", () => {
const block =
`command.update { name = "Mixed", key = "Ctrl-a", mac = { "Cmd-a", "Cmd-A" } }`;
const { commandOverrides } = parseManagedBlock(block);
expect(commandOverrides).toEqual({
"Mixed": { key: "Ctrl-a", mac: ["Cmd-a", "Cmd-A"] },
});
});
test("round-trips the shape saveConfiguration emits", () => {
const configOverrides = {
shortWikiLinks: false,
"smartQuotes.enabled": true,
autoCloseBrackets: "([{",
};
const commandOverrides: Record<
string,
{ key?: string | string[]; mac?: string | string[] }
> = {
"Some: Command": { key: "Ctrl-x", mac: "Cmd-x" },
"Chord Cmd": { key: "Ctrl-x Ctrl-s", mac: "Cmd-x Cmd-s" },
"Array Cmd": { key: ["Ctrl-y", "Ctrl-Y"] },
"Other": { key: "Ctrl-y" },
};
const lines: string[] = ["-- managed-by: configuration-manager"];
for (const [path, value] of Object.entries(configOverrides)) {
lines.push(`config.set(${toLua(path)}, ${toLua(value)})`);
}
for (const [name, override] of Object.entries(commandOverrides)) {
const parts = [`name = ${toLua(name)}`];
if (override.key !== undefined) parts.push(`key = ${toLua(override.key)}`);
if (override.mac !== undefined) parts.push(`mac = ${toLua(override.mac)}`);
lines.push(`command.update { ${parts.join(", ")} }`);
}
const parsed = parseManagedBlock(lines.join("\n"));
expect(parsed.configOverrides).toEqual(configOverrides);
expect(parsed.commandOverrides).toEqual(commandOverrides);
});
});