From f2eefa307eade630339433a684a8633de31e9c49 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 8 Apr 2026 10:04:20 +0000 Subject: [PATCH] test: add coverage for dotenv parse, remove, and append helpers Exercises the shared lib used by secrets TRPC and file workspace: comments/CRLF handling, quoting, duplicate key rejection, and line formatting for append. --- src/lib/dotenv-parse.test.ts | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/lib/dotenv-parse.test.ts diff --git a/src/lib/dotenv-parse.test.ts b/src/lib/dotenv-parse.test.ts new file mode 100644 index 0000000..ebb7511 --- /dev/null +++ b/src/lib/dotenv-parse.test.ts @@ -0,0 +1,85 @@ +import { describe, expect, it } from "vitest"; +import { appendDotenvKey, parseDotenv, removeDotenvKey } from "./dotenv-parse"; + +describe("parseDotenv", () => { + it("ignores blanks and # comments", () => { + expect(parseDotenv("\n \n# x=1\nFOO=bar\n")).toEqual([ + { key: "FOO", value: "bar" }, + ]); + }); + + it("parses unquoted and quoted values", () => { + expect(parseDotenv(`A=1\nB='2'\nC="3"`)).toEqual([ + { key: "A", value: "1" }, + { key: "B", value: "2" }, + { key: "C", value: "3" }, + ]); + }); + + it("splits on CRLF and skips malformed lines", () => { + expect(parseDotenv("OK=yes\r\n=bad\nNOEQ\nALSO=ok")).toEqual([ + { key: "OK", value: "yes" }, + { key: "ALSO", value: "ok" }, + ]); + }); + + it("trims keys and values around =", () => { + expect(parseDotenv(" KEY = val ")).toEqual([ + { key: "KEY", value: "val" }, + ]); + }); +}); + +describe("removeDotenvKey", () => { + it("drops assignment lines for the key and keeps comments and spacing lines", () => { + const src = "# keep\n\nSECRET=x\nOTHER=1\n"; + expect(removeDotenvKey(src, "SECRET")).toBe("# keep\n\nOTHER=1\n"); + }); + + it("removes every line parseDotenv would attribute to that key", () => { + const src = "DUP=a\nDUP=b\n"; + expect(removeDotenvKey(src, "DUP")).toBe(""); + }); +}); + +describe("appendDotenvKey", () => { + it("appends a line to empty content", () => { + expect(appendDotenvKey("", "K", "v")).toEqual({ + ok: true, + content: "K=v", + }); + }); + + it("trims trailing whitespace and joins with a single newline", () => { + expect(appendDotenvKey("A=1\n\n \t", "B", "2")).toEqual({ + ok: true, + content: "A=1\nB=2", + }); + }); + + it("quotes values that need escaping", () => { + expect(appendDotenvKey("", "K", `say "hi"`)).toEqual({ + ok: true, + content: `K="say \\"hi\\""`, + }); + }); + + it("rejects invalid keys and newlines in the value", () => { + expect(appendDotenvKey("", "", "x").ok).toBe(false); + expect(appendDotenvKey("", "a=b", "x").ok).toBe(false); + expect(appendDotenvKey("", "#x", "1").ok).toBe(false); + expect(appendDotenvKey("", "bad\nkey", "1").ok).toBe(false); + expect(appendDotenvKey("", "K", "a\nb").ok).toBe(false); + }); + + it("rejects duplicate keys visible to parseDotenv", () => { + const r = appendDotenvKey("FOO=1", "FOO", "2"); + expect(r.ok).toBe(false); + if (!r.ok) expect(r.error).toContain("FOO"); + }); + + it("treats trimmed key as duplicate of existing assignment", () => { + const r = appendDotenvKey("FOO=1", " FOO ", "2"); + expect(r.ok).toBe(false); + }); +});