diff --git a/tests/args.test.mjs b/tests/args.test.mjs new file mode 100644 index 0000000..68c67ef --- /dev/null +++ b/tests/args.test.mjs @@ -0,0 +1,70 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { parseArgs, splitRawArgumentString } from "../plugins/codex/scripts/lib/args.mjs"; + +// --- parseArgs --- + +test("parseArgs: boolean flag --flag=true sets true, --flag=false sets false", () => { + const configTrue = parseArgs(["--verbose=true"], { booleanOptions: ["verbose"] }); + assert.equal(configTrue.options.verbose, true); + + const configFalse = parseArgs(["--verbose=false"], { booleanOptions: ["verbose"] }); + assert.equal(configFalse.options.verbose, false); +}); + +test("parseArgs: value option --output consumes next token", () => { + const { options } = parseArgs(["--output", "/tmp/out.txt"], { valueOptions: ["output"] }); + assert.equal(options.output, "/tmp/out.txt"); +}); + +test("parseArgs: inline value --output=path uses inline value", () => { + const { options } = parseArgs(["--output=/tmp/out.txt"], { valueOptions: ["output"] }); + assert.equal(options.output, "/tmp/out.txt"); +}); + +test("parseArgs: short alias -o resolved via aliasMap", () => { + const { options } = parseArgs(["-o", "/tmp/out.txt"], { + valueOptions: ["output"], + aliasMap: { o: "output" }, + }); + assert.equal(options.output, "/tmp/out.txt"); +}); + +test("parseArgs: positionals after -- land in positionals array", () => { + const { options, positionals } = parseArgs( + ["--verbose", "--", "--not-a-flag", "file.txt"], + { booleanOptions: ["verbose"] } + ); + assert.equal(options.verbose, true); + assert.deepEqual(positionals, ["--not-a-flag", "file.txt"]); +}); + +test("parseArgs: missing value for value option throws Error", () => { + assert.throws( + () => parseArgs(["--output"], { valueOptions: ["output"] }), + { message: "Missing value for --output" } + ); +}); + +// --- splitRawArgumentString --- + +test("splitRawArgumentString: space-separated tokens", () => { + assert.deepEqual(splitRawArgumentString("foo bar baz"), ["foo", "bar", "baz"]); +}); + +test("splitRawArgumentString: single-quoted string with spaces becomes one token", () => { + assert.deepEqual(splitRawArgumentString("hello 'foo bar' world"), ["hello", "foo bar", "world"]); +}); + +test("splitRawArgumentString: double-quoted string with spaces becomes one token", () => { + assert.deepEqual(splitRawArgumentString('hello "foo bar" world'), ["hello", "foo bar", "world"]); +}); + +test("splitRawArgumentString: backslash escape preserves next char", () => { + assert.deepEqual(splitRawArgumentString("foo\\ bar baz"), ["foo bar", "baz"]); +}); + +test("splitRawArgumentString: trailing backslash appended literally", () => { + assert.deepEqual(splitRawArgumentString("foo\\"), ["foo\\"]); +}); diff --git a/tests/prompts.test.mjs b/tests/prompts.test.mjs new file mode 100644 index 0000000..3fb7fba --- /dev/null +++ b/tests/prompts.test.mjs @@ -0,0 +1,25 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { interpolateTemplate } from "../plugins/codex/scripts/lib/prompts.mjs"; + +test("interpolateTemplate: replaces {{KEY}} with provided variable", () => { + assert.equal(interpolateTemplate("Hello {{NAME}}", { NAME: "World" }), "Hello World"); +}); + +test("interpolateTemplate: replaces multiple different keys in one pass", () => { + const result = interpolateTemplate("{{GREETING}}, {{NAME}}!", { GREETING: "Hi", NAME: "Alice" }); + assert.equal(result, "Hi, Alice!"); +}); + +test("interpolateTemplate: unknown key is replaced with empty string", () => { + assert.equal(interpolateTemplate("Hello {{MISSING}}", {}), "Hello "); +}); + +test("interpolateTemplate: template with no placeholders is returned unchanged", () => { + assert.equal(interpolateTemplate("no placeholders here", { KEY: "val" }), "no placeholders here"); +}); + +test("interpolateTemplate: key appearing twice is replaced both times", () => { + assert.equal(interpolateTemplate("{{X}} and {{X}}", { X: "ok" }), "ok and ok"); +});