Skip to content

Commit 2b55435

Browse files
anandgupta42claude
andcommitted
test: command builtins + sql_analyze formatting — 16 new tests
Cover altimate-specific builtin commands (discover-and-add-mcps, configure-claude, configure-codex) and Command.hints() parsing that had zero test coverage. Also cover SqlAnalyzeTool title construction and formatAnalysis output formatting to prevent regression of the success-flag telemetry fix (38bfb52). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 544903f commit 2b55435

2 files changed

Lines changed: 288 additions & 0 deletions

File tree

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/**
2+
* Tests for SqlAnalyzeTool title construction and formatAnalysis output.
3+
*
4+
* These test the formatting logic patterns used in sql-analyze.ts.
5+
* Since formatAnalysis is not exported, we replicate its logic here —
6+
* same approach as tool-formatters.test.ts. This means these tests
7+
* will not catch changes to the real function unless the test copy
8+
* is also updated. This is an accepted tradeoff in this codebase.
9+
*/
10+
11+
import { describe, test, expect } from "bun:test"
12+
13+
describe("SqlAnalyzeTool: title construction", () => {
14+
// Replicates the title template from sql-analyze.ts execute() line 25
15+
function buildTitle(result: { error?: string; issue_count: number; confidence: string }) {
16+
return `Analyze: ${result.error ? "PARSE ERROR" : `${result.issue_count} issue${result.issue_count !== 1 ? "s" : ""}`} [${result.confidence}]`
17+
}
18+
19+
test("zero issues shows '0 issues'", () => {
20+
expect(buildTitle({ issue_count: 0, confidence: "high" })).toBe("Analyze: 0 issues [high]")
21+
})
22+
23+
test("one issue shows singular '1 issue'", () => {
24+
expect(buildTitle({ issue_count: 1, confidence: "high" })).toBe("Analyze: 1 issue [high]")
25+
})
26+
27+
test("multiple issues shows plural", () => {
28+
expect(buildTitle({ issue_count: 5, confidence: "medium" })).toBe("Analyze: 5 issues [medium]")
29+
})
30+
31+
test("error present shows PARSE ERROR", () => {
32+
expect(buildTitle({ error: "syntax error", issue_count: 0, confidence: "low" })).toBe(
33+
"Analyze: PARSE ERROR [low]",
34+
)
35+
})
36+
})
37+
38+
describe("SqlAnalyzeTool: formatAnalysis output", () => {
39+
// Replicates formatAnalysis() from sql-analyze.ts lines 45-70
40+
function formatAnalysis(result: {
41+
error?: string
42+
issues: Array<{
43+
type: string
44+
severity: string
45+
message: string
46+
recommendation: string
47+
location?: string
48+
confidence: string
49+
}>
50+
issue_count: number
51+
confidence: string
52+
confidence_factors: string[]
53+
}): string {
54+
if (result.error) return `Analysis failed: ${result.error}`
55+
if (result.issues.length === 0) return "No anti-patterns or issues detected."
56+
57+
const lines: string[] = [
58+
`Found ${result.issue_count} issue${result.issue_count !== 1 ? "s" : ""} (confidence: ${result.confidence}):`,
59+
]
60+
if (result.confidence_factors.length > 0) {
61+
lines.push(` Note: ${result.confidence_factors.join("; ")}`)
62+
}
63+
lines.push("")
64+
65+
for (const issue of result.issues) {
66+
const loc = issue.location ? ` \u2014 ${issue.location}` : ""
67+
const conf = issue.confidence !== "high" ? ` [${issue.confidence} confidence]` : ""
68+
lines.push(` [${issue.severity.toUpperCase()}] ${issue.type}${conf}`)
69+
lines.push(` ${issue.message}${loc}`)
70+
lines.push(` \u2192 ${issue.recommendation}`)
71+
lines.push("")
72+
}
73+
74+
return lines.join("\n")
75+
}
76+
77+
test("error result returns failure message", () => {
78+
const output = formatAnalysis({
79+
error: "parse error at line 5",
80+
issues: [],
81+
issue_count: 0,
82+
confidence: "low",
83+
confidence_factors: [],
84+
})
85+
expect(output).toBe("Analysis failed: parse error at line 5")
86+
})
87+
88+
test("zero issues returns clean message", () => {
89+
const output = formatAnalysis({
90+
issues: [],
91+
issue_count: 0,
92+
confidence: "high",
93+
confidence_factors: [],
94+
})
95+
expect(output).toBe("No anti-patterns or issues detected.")
96+
})
97+
98+
test("issues are formatted with severity, type, location", () => {
99+
const output = formatAnalysis({
100+
issues: [
101+
{
102+
type: "lint",
103+
severity: "warning",
104+
message: "SELECT * detected",
105+
recommendation: "Use explicit columns",
106+
location: "line 1",
107+
confidence: "high",
108+
},
109+
],
110+
issue_count: 1,
111+
confidence: "high",
112+
confidence_factors: ["lint"],
113+
})
114+
expect(output).toContain("[WARNING] lint")
115+
expect(output).toContain("SELECT * detected \u2014 line 1")
116+
expect(output).toContain("\u2192 Use explicit columns")
117+
})
118+
119+
test("non-high confidence issues show confidence tag", () => {
120+
const output = formatAnalysis({
121+
issues: [
122+
{
123+
type: "semantic",
124+
severity: "info",
125+
message: "Possible unused join",
126+
recommendation: "Review join necessity",
127+
confidence: "medium",
128+
},
129+
],
130+
issue_count: 1,
131+
confidence: "medium",
132+
confidence_factors: ["semantics"],
133+
})
134+
expect(output).toContain("[medium confidence]")
135+
})
136+
137+
test("high confidence issues omit confidence tag", () => {
138+
const output = formatAnalysis({
139+
issues: [
140+
{
141+
type: "safety",
142+
severity: "high",
143+
message: "SQL injection risk",
144+
recommendation: "Use parameterized queries",
145+
confidence: "high",
146+
},
147+
],
148+
issue_count: 1,
149+
confidence: "high",
150+
confidence_factors: ["safety"],
151+
})
152+
expect(output).not.toContain("[high confidence]")
153+
})
154+
155+
test("confidence factors are listed in Note line", () => {
156+
const output = formatAnalysis({
157+
issues: [
158+
{
159+
type: "lint",
160+
severity: "warning",
161+
message: "Missing LIMIT",
162+
recommendation: "Add LIMIT clause",
163+
confidence: "high",
164+
},
165+
],
166+
issue_count: 1,
167+
confidence: "high",
168+
confidence_factors: ["lint", "semantics", "safety"],
169+
})
170+
expect(output).toContain("Note: lint; semantics; safety")
171+
})
172+
})
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { describe, test, expect } from "bun:test"
2+
import { Command } from "../../src/command/index"
3+
import { Instance } from "../../src/project/instance"
4+
import { tmpdir } from "../fixture/fixture"
5+
6+
async function withInstance(fn: () => Promise<void>) {
7+
await using tmp = await tmpdir({ git: true })
8+
await Instance.provide({ directory: tmp.path, fn })
9+
}
10+
11+
describe("altimate builtin commands", () => {
12+
describe("discover-and-add-mcps", () => {
13+
test("is registered as a default command", async () => {
14+
await withInstance(async () => {
15+
const cmd = await Command.get("discover-and-add-mcps")
16+
expect(cmd).toBeDefined()
17+
expect(cmd.name).toBe("discover-and-add-mcps")
18+
expect(cmd.source).toBe("command")
19+
})
20+
})
21+
22+
test("has correct description", async () => {
23+
await withInstance(async () => {
24+
const cmd = await Command.get("discover-and-add-mcps")
25+
expect(cmd.description).toBe("discover MCP servers from external AI tool configs and add them")
26+
})
27+
})
28+
29+
test("template references MCP discovery workflow", async () => {
30+
await withInstance(async () => {
31+
const cmd = await Command.get("discover-and-add-mcps")
32+
const template = await cmd.template
33+
expect(typeof template).toBe("string")
34+
expect(template.length).toBeGreaterThan(0)
35+
// The template should reference MCP-related concepts
36+
expect(template.toLowerCase()).toContain("mcp")
37+
})
38+
})
39+
40+
test("is present in Command.Default constants", () => {
41+
expect(Command.Default.DISCOVER_MCPS).toBe("discover-and-add-mcps")
42+
})
43+
})
44+
45+
describe("configure-claude", () => {
46+
test("is registered as a default command", async () => {
47+
await withInstance(async () => {
48+
const cmd = await Command.get("configure-claude")
49+
expect(cmd).toBeDefined()
50+
expect(cmd.name).toBe("configure-claude")
51+
expect(cmd.source).toBe("command")
52+
})
53+
})
54+
55+
test("has correct description", async () => {
56+
await withInstance(async () => {
57+
const cmd = await Command.get("configure-claude")
58+
expect(cmd.description).toBe("configure /altimate command in Claude Code")
59+
})
60+
})
61+
62+
test("is present in Command.Default constants", () => {
63+
expect(Command.Default.CONFIGURE_CLAUDE).toBe("configure-claude")
64+
})
65+
})
66+
67+
describe("configure-codex", () => {
68+
test("is registered as a default command", async () => {
69+
await withInstance(async () => {
70+
const cmd = await Command.get("configure-codex")
71+
expect(cmd).toBeDefined()
72+
expect(cmd.name).toBe("configure-codex")
73+
expect(cmd.source).toBe("command")
74+
})
75+
})
76+
77+
test("has correct description", async () => {
78+
await withInstance(async () => {
79+
const cmd = await Command.get("configure-codex")
80+
expect(cmd.description).toBe("configure altimate skill in Codex CLI")
81+
})
82+
})
83+
84+
test("is present in Command.Default constants", () => {
85+
expect(Command.Default.CONFIGURE_CODEX).toBe("configure-codex")
86+
})
87+
})
88+
})
89+
90+
describe("Command.hints()", () => {
91+
test("extracts numbered placeholders in order", () => {
92+
expect(Command.hints("Do $1 then $2")).toEqual(["$1", "$2"])
93+
})
94+
95+
test("extracts $ARGUMENTS", () => {
96+
expect(Command.hints("Run with $ARGUMENTS")).toEqual(["$ARGUMENTS"])
97+
})
98+
99+
test("extracts both numbered and $ARGUMENTS", () => {
100+
expect(Command.hints("Do $1 with $ARGUMENTS")).toEqual(["$1", "$ARGUMENTS"])
101+
})
102+
103+
test("deduplicates repeated placeholders", () => {
104+
expect(Command.hints("$1 and $1 again")).toEqual(["$1"])
105+
})
106+
107+
test("returns empty array for no placeholders", () => {
108+
expect(Command.hints("plain text")).toEqual([])
109+
})
110+
111+
test("sorts numbered placeholders lexicographically", () => {
112+
// Note: uses .sort() with no comparator, so $10 sorts before $2.
113+
// For single-digit placeholders, lexicographic order matches numeric.
114+
expect(Command.hints("$3 then $1 then $2")).toEqual(["$1", "$2", "$3"])
115+
})
116+
})

0 commit comments

Comments
 (0)