diff --git a/__tests__/amass-plugin.test.js b/__tests__/amass-plugin.test.js new file mode 100644 index 000000000..ce45a9223 --- /dev/null +++ b/__tests__/amass-plugin.test.js @@ -0,0 +1,73 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeAmassBinary(dir) { + const bin = path.join(dir, "amass") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('amass v5.0.0-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("amass plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-amass-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-amass-")) + writeFakeAmassBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/amass --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove amass --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("amass enum -d example.com --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("amass.passthrough") + expect(data.data.args).toContain("enum") + expect(data.data.args).toContain("-d") + expect(data.data.args).toContain("example.com") + }) + + test("doctor reports amass dependency as healthy", () => { + const r = runNoServer("plugins doctor amass --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "amass" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/goss-plugin.test.js b/__tests__/goss-plugin.test.js new file mode 100644 index 000000000..208fa911a --- /dev/null +++ b/__tests__/goss-plugin.test.js @@ -0,0 +1,73 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeGossBinary(dir) { + const bin = path.join(dir, "goss") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('goss 0.4.9-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("goss plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-goss-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-goss-")) + writeFakeGossBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/goss --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove goss --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("goss validate --format documentation --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("goss.passthrough") + expect(data.data.args).toContain("validate") + expect(data.data.args).toContain("--format") + expect(data.data.args).toContain("documentation") + }) + + test("doctor reports goss dependency as healthy", () => { + const r = runNoServer("plugins doctor goss --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "goss" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/hivemind-plugin.test.js b/__tests__/hivemind-plugin.test.js new file mode 100644 index 000000000..a7012b385 --- /dev/null +++ b/__tests__/hivemind-plugin.test.js @@ -0,0 +1,71 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeHivemindBinary(dir) { + const bin = path.join(dir, "hivemind") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('Hivemind 1.1.0-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("hivemind plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-hivemind-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-hivemind-")) + writeFakeHivemindBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/hivemind --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove hivemind --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("hivemind Procfile.dev --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("hivemind.passthrough") + expect(data.data.args).toContain("Procfile.dev") + }) + + test("doctor reports hivemind dependency as healthy", () => { + const r = runNoServer("plugins doctor hivemind --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "hivemind" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/mods-plugin.test.js b/__tests__/mods-plugin.test.js new file mode 100644 index 000000000..7d4c215bb --- /dev/null +++ b/__tests__/mods-plugin.test.js @@ -0,0 +1,72 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeModsBinary(dir) { + const bin = path.join(dir, "mods") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('mods version 1.7.0-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("mods plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-mods-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-mods-")) + writeFakeModsBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/mods --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove mods --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("mods --model gpt-4 --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("mods.passthrough") + expect(data.data.args).toContain("--model") + expect(data.data.args).toContain("gpt-4") + }) + + test("doctor reports mods dependency as healthy", () => { + const r = runNoServer("plugins doctor mods --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "mods" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/tlrc-plugin.test.js b/__tests__/tlrc-plugin.test.js new file mode 100644 index 000000000..307249126 --- /dev/null +++ b/__tests__/tlrc-plugin.test.js @@ -0,0 +1,81 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +// tlrc ships the official tldr client, so the binary on PATH is named `tldr`. +function writeFakeTldrBinary(dir) { + const bin = path.join(dir, "tldr") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('tlrc 1.11.0-test'); process.exit(0); }", + "if (args[0] === '--list') { console.log('tar\\nzip\\ngit'); process.exit(0); }", + "console.log('Page for ' + args.join(' '));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("tlrc plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-tlrc-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-tlrc-")) + writeFakeTldrBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/tlrc --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove tlrc --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("routes self version wrapped command", () => { + const r = runNoServer("tldr self version --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("tldr.self.version") + expect(data.data.raw).toBe("tlrc 1.11.0-test") + }) + + test("routes cache list wrapped command", () => { + const r = runNoServer("tldr cache list --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("tldr.cache.list") + expect(data.data.raw).toContain("git") + }) + + test("doctor reports tldr dependency as healthy", () => { + const r = runNoServer("plugins doctor tlrc --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "tldr" && c.ok === true)).toBe(true) + }) +})