diff --git a/src/channels/channel-config.test.ts b/src/channels/channel-config.test.ts index 5fa81b0b955..317759052c1 100644 --- a/src/channels/channel-config.test.ts +++ b/src/channels/channel-config.test.ts @@ -42,44 +42,44 @@ describe("resolveChannelEntryMatch", () => { }); describe("resolveChannelEntryMatchWithFallback", () => { - it("prefers direct matches over parent and wildcard", () => { - const entries = { a: { allow: true }, parent: { allow: false }, "*": { allow: false } }; - const match = resolveChannelEntryMatchWithFallback({ - entries, - keys: ["a"], - parentKeys: ["parent"], - wildcardKey: "*", - }); - expect(match.entry).toBe(entries.a); - expect(match.matchSource).toBe("direct"); - expect(match.matchKey).toBe("a"); - }); + const fallbackCases = [ + { + name: "prefers direct matches over parent and wildcard", + entries: { a: { allow: true }, parent: { allow: false }, "*": { allow: false } }, + args: { keys: ["a"], parentKeys: ["parent"], wildcardKey: "*" }, + expectedEntryKey: "a", + expectedSource: "direct", + expectedMatchKey: "a", + }, + { + name: "falls back to parent when direct misses", + entries: { parent: { allow: false }, "*": { allow: true } }, + args: { keys: ["missing"], parentKeys: ["parent"], wildcardKey: "*" }, + expectedEntryKey: "parent", + expectedSource: "parent", + expectedMatchKey: "parent", + }, + { + name: "falls back to wildcard when no direct or parent match", + entries: { "*": { allow: true } }, + args: { keys: ["missing"], parentKeys: ["still-missing"], wildcardKey: "*" }, + expectedEntryKey: "*", + expectedSource: "wildcard", + expectedMatchKey: "*", + }, + ] as const; - it("falls back to parent when direct misses", () => { - const entries = { parent: { allow: false }, "*": { allow: true } }; - const match = resolveChannelEntryMatchWithFallback({ - entries, - keys: ["missing"], - parentKeys: ["parent"], - wildcardKey: "*", + for (const testCase of fallbackCases) { + it(testCase.name, () => { + const match = resolveChannelEntryMatchWithFallback({ + entries: testCase.entries, + ...testCase.args, + }); + expect(match.entry).toBe(testCase.entries[testCase.expectedEntryKey]); + expect(match.matchSource).toBe(testCase.expectedSource); + expect(match.matchKey).toBe(testCase.expectedMatchKey); }); - expect(match.entry).toBe(entries.parent); - expect(match.matchSource).toBe("parent"); - expect(match.matchKey).toBe("parent"); - }); - - it("falls back to wildcard when no direct or parent match", () => { - const entries = { "*": { allow: true } }; - const match = resolveChannelEntryMatchWithFallback({ - entries, - keys: ["missing"], - parentKeys: ["still-missing"], - wildcardKey: "*", - }); - expect(match.entry).toBe(entries["*"]); - expect(match.matchSource).toBe("wildcard"); - expect(match.matchKey).toBe("*"); - }); + } it("matches normalized keys when normalizeKey is provided", () => { const entries = { "My Team": { allow: true } }; @@ -153,44 +153,52 @@ describe("validateSenderIdentity", () => { }); describe("resolveNestedAllowlistDecision", () => { - it("allows when outer allowlist is disabled", () => { - expect( - resolveNestedAllowlistDecision({ + const cases = [ + { + name: "allows when outer allowlist is disabled", + value: { outerConfigured: false, outerMatched: false, innerConfigured: false, innerMatched: false, - }), - ).toBe(true); - }); - - it("blocks when outer allowlist is configured but missing match", () => { - expect( - resolveNestedAllowlistDecision({ + }, + expected: true, + }, + { + name: "blocks when outer allowlist is configured but missing match", + value: { outerConfigured: true, outerMatched: false, innerConfigured: false, innerMatched: false, - }), - ).toBe(false); - }); - - it("requires inner match when inner allowlist is configured", () => { - expect( - resolveNestedAllowlistDecision({ + }, + expected: false, + }, + { + name: "requires inner match when inner allowlist is configured", + value: { outerConfigured: true, outerMatched: true, innerConfigured: true, innerMatched: false, - }), - ).toBe(false); - expect( - resolveNestedAllowlistDecision({ + }, + expected: false, + }, + { + name: "allows when both outer and inner allowlists match", + value: { outerConfigured: true, outerMatched: true, innerConfigured: true, innerMatched: true, - }), - ).toBe(true); - }); + }, + expected: true, + }, + ] as const; + + for (const testCase of cases) { + it(testCase.name, () => { + expect(resolveNestedAllowlistDecision(testCase.value)).toBe(testCase.expected); + }); + } }); diff --git a/src/utils/reaction-level.test.ts b/src/utils/reaction-level.test.ts index ade1fe5dd8c..ec5cedb2e9f 100644 --- a/src/utils/reaction-level.test.ts +++ b/src/utils/reaction-level.test.ts @@ -2,52 +2,64 @@ import { describe, expect, it } from "vitest"; import { resolveReactionLevel } from "./reaction-level.js"; describe("resolveReactionLevel", () => { - it("defaults when value is missing", () => { - expect( - resolveReactionLevel({ value: undefined, defaultLevel: "minimal", invalidFallback: "ack" }), - ).toEqual({ - level: "minimal", - ackEnabled: false, - agentReactionsEnabled: true, - agentReactionGuidance: "minimal", - }); - }); - - it("supports ack", () => { - expect( - resolveReactionLevel({ value: "ack", defaultLevel: "minimal", invalidFallback: "ack" }), - ).toEqual({ level: "ack", ackEnabled: true, agentReactionsEnabled: false }); - }); - - it("supports extensive", () => { - expect( - resolveReactionLevel({ + const cases = [ + { + name: "defaults when value is missing", + input: { + value: undefined, + defaultLevel: "minimal" as const, + invalidFallback: "ack" as const, + }, + expected: { + level: "minimal", + ackEnabled: false, + agentReactionsEnabled: true, + agentReactionGuidance: "minimal", + }, + }, + { + name: "supports ack", + input: { value: "ack", defaultLevel: "minimal" as const, invalidFallback: "ack" as const }, + expected: { level: "ack", ackEnabled: true, agentReactionsEnabled: false }, + }, + { + name: "supports extensive", + input: { value: "extensive", - defaultLevel: "minimal", - invalidFallback: "ack", - }), - ).toEqual({ - level: "extensive", - ackEnabled: false, - agentReactionsEnabled: true, - agentReactionGuidance: "extensive", - }); - }); + defaultLevel: "minimal" as const, + invalidFallback: "ack" as const, + }, + expected: { + level: "extensive", + ackEnabled: false, + agentReactionsEnabled: true, + agentReactionGuidance: "extensive", + }, + }, + { + name: "uses invalid fallback ack", + input: { value: "bogus", defaultLevel: "minimal" as const, invalidFallback: "ack" as const }, + expected: { level: "ack", ackEnabled: true, agentReactionsEnabled: false }, + }, + { + name: "uses invalid fallback minimal", + input: { + value: "bogus", + defaultLevel: "minimal" as const, + invalidFallback: "minimal" as const, + }, + expected: { + level: "minimal", + ackEnabled: false, + agentReactionsEnabled: true, + agentReactionGuidance: "minimal", + }, + }, + ] as const; - it("uses invalid fallback ack", () => { - expect( - resolveReactionLevel({ value: "bogus", defaultLevel: "minimal", invalidFallback: "ack" }), - ).toEqual({ level: "ack", ackEnabled: true, agentReactionsEnabled: false }); - }); - - it("uses invalid fallback minimal", () => { - expect( - resolveReactionLevel({ value: "bogus", defaultLevel: "minimal", invalidFallback: "minimal" }), - ).toEqual({ - level: "minimal", - ackEnabled: false, - agentReactionsEnabled: true, - agentReactionGuidance: "minimal", + for (const testCase of cases) { + it(testCase.name, () => { + expect(resolveReactionLevel(testCase.input)).toEqual(testCase.expected); }); - }); + } }); diff --git a/src/utils/utils-misc.test.ts b/src/utils/utils-misc.test.ts index 1c8a1632285..602db3f6f57 100644 --- a/src/utils/utils-misc.test.ts +++ b/src/utils/utils-misc.test.ts @@ -43,40 +43,48 @@ describe("parseBooleanValue", () => { }); describe("isReasoningTagProvider", () => { - it("returns false for ollama - native reasoning field, no tags needed (#2279)", () => { - expect(isReasoningTagProvider("ollama")).toBe(false); - expect(isReasoningTagProvider("Ollama")).toBe(false); - }); + const cases: Array<{ + name: string; + value: string | null | undefined; + expected: boolean; + }> = [ + { + name: "returns false for ollama - native reasoning field, no tags needed (#2279)", + value: "ollama", + expected: false, + }, + { + name: "returns false for case-insensitive ollama", + value: "Ollama", + expected: false, + }, + { name: "returns true for google-gemini-cli", value: "google-gemini-cli", expected: true }, + { + name: "returns true for google-generative-ai", + value: "google-generative-ai", + expected: true, + }, + { name: "returns true for google-antigravity", value: "google-antigravity", expected: true }, + { + name: "returns true for google-antigravity model suffixes", + value: "google-antigravity/gemini-3", + expected: true, + }, + { name: "returns true for minimax", value: "minimax", expected: true }, + { name: "returns true for minimax-cn", value: "minimax-cn", expected: true }, + { name: "returns false for null", value: null, expected: false }, + { name: "returns false for undefined", value: undefined, expected: false }, + { name: "returns false for empty", value: "", expected: false }, + { name: "returns false for anthropic", value: "anthropic", expected: false }, + { name: "returns false for openai", value: "openai", expected: false }, + { name: "returns false for openrouter", value: "openrouter", expected: false }, + ]; - it("returns true for google-gemini-cli", () => { - expect(isReasoningTagProvider("google-gemini-cli")).toBe(true); - }); - - it("returns true for google-generative-ai", () => { - expect(isReasoningTagProvider("google-generative-ai")).toBe(true); - }); - - it("returns true for google-antigravity", () => { - expect(isReasoningTagProvider("google-antigravity")).toBe(true); - expect(isReasoningTagProvider("google-antigravity/gemini-3")).toBe(true); - }); - - it("returns true for minimax", () => { - expect(isReasoningTagProvider("minimax")).toBe(true); - expect(isReasoningTagProvider("minimax-cn")).toBe(true); - }); - - it("returns false for null/undefined/empty", () => { - expect(isReasoningTagProvider(null)).toBe(false); - expect(isReasoningTagProvider(undefined)).toBe(false); - expect(isReasoningTagProvider("")).toBe(false); - }); - - it("returns false for standard providers", () => { - expect(isReasoningTagProvider("anthropic")).toBe(false); - expect(isReasoningTagProvider("openai")).toBe(false); - expect(isReasoningTagProvider("openrouter")).toBe(false); - }); + for (const testCase of cases) { + it(testCase.name, () => { + expect(isReasoningTagProvider(testCase.value)).toBe(testCase.expected); + }); + } }); describe("splitShellArgs", () => {