Agent behavior improvements: - Add project context detection (tsconfig.json, pom.xml, etc.) - Enforce validation after changes (tsc --noEmit, mvn compile, etc.) - Run tests automatically - never ask "do you want me to run tests" - Complete full loop: create → type-check → test → confirm - Add command detection for direct execution (run tree, run ls) Diff view improvements: - Use darker backgrounds for added/removed lines - Add diffLineBgAdded, diffLineBgRemoved, diffLineText theme colors - Improve text visibility with white text on dark backgrounds - Update both React/Ink and SolidJS diff components Streaming fixes: - Fix tool call argument accumulation using OpenAI index field - Fix streaming content display after tool calls - Add consecutive error tracking to prevent token waste Other changes: - ESC to abort operations, Ctrl+C to exit - Fix model selection when provider changes in cascade mode - Add debug logging for troubleshooting - Move tests to root tests/ folder - Fix banner test GRADIENT_COLORS reference
187 lines
5.2 KiB
TypeScript
187 lines
5.2 KiB
TypeScript
/**
|
|
* Unit tests for Permission Pattern Index
|
|
*/
|
|
|
|
import { describe, it, expect } from "bun:test";
|
|
|
|
import {
|
|
createPatternIndex,
|
|
buildPatternIndex,
|
|
addToIndex,
|
|
removeFromIndex,
|
|
getPatternsForTool,
|
|
hasPattern,
|
|
getRawPatterns,
|
|
mergeIndexes,
|
|
getIndexStats,
|
|
} from "@services/permissions/pattern-index";
|
|
|
|
describe("Permission Pattern Index", () => {
|
|
describe("createPatternIndex", () => {
|
|
it("should create empty index", () => {
|
|
const index = createPatternIndex();
|
|
|
|
expect(index.all).toHaveLength(0);
|
|
expect(index.byTool.size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("buildPatternIndex", () => {
|
|
it("should build index from patterns", () => {
|
|
const patterns = [
|
|
"Bash(git:*)",
|
|
"Bash(npm install:*)",
|
|
"Read(*)",
|
|
"Write(src/*)",
|
|
];
|
|
|
|
const index = buildPatternIndex(patterns);
|
|
|
|
expect(index.all).toHaveLength(4);
|
|
expect(index.byTool.get("Bash")).toHaveLength(2);
|
|
expect(index.byTool.get("Read")).toHaveLength(1);
|
|
expect(index.byTool.get("Write")).toHaveLength(1);
|
|
});
|
|
|
|
it("should skip invalid patterns", () => {
|
|
const patterns = ["Bash(git:*)", "invalid pattern", "Read(*)"];
|
|
|
|
const index = buildPatternIndex(patterns);
|
|
|
|
expect(index.all).toHaveLength(2);
|
|
});
|
|
|
|
it("should handle empty array", () => {
|
|
const index = buildPatternIndex([]);
|
|
|
|
expect(index.all).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("addToIndex", () => {
|
|
it("should add pattern to index", () => {
|
|
let index = createPatternIndex();
|
|
index = addToIndex(index, "Bash(git:*)");
|
|
|
|
expect(index.all).toHaveLength(1);
|
|
expect(hasPattern(index, "Bash(git:*)")).toBe(true);
|
|
});
|
|
|
|
it("should not duplicate patterns", () => {
|
|
let index = buildPatternIndex(["Bash(git:*)"]);
|
|
index = addToIndex(index, "Bash(git:*)");
|
|
|
|
expect(index.all).toHaveLength(1);
|
|
});
|
|
|
|
it("should add to correct tool bucket", () => {
|
|
let index = createPatternIndex();
|
|
index = addToIndex(index, "Read(src/*)");
|
|
|
|
expect(getPatternsForTool(index, "Read")).toHaveLength(1);
|
|
expect(getPatternsForTool(index, "Bash")).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("removeFromIndex", () => {
|
|
it("should remove pattern from index", () => {
|
|
let index = buildPatternIndex(["Bash(git:*)", "Read(*)"]);
|
|
index = removeFromIndex(index, "Bash(git:*)");
|
|
|
|
expect(index.all).toHaveLength(1);
|
|
expect(hasPattern(index, "Bash(git:*)")).toBe(false);
|
|
expect(hasPattern(index, "Read(*)")).toBe(true);
|
|
});
|
|
|
|
it("should handle non-existent pattern", () => {
|
|
const index = buildPatternIndex(["Bash(git:*)"]);
|
|
const result = removeFromIndex(index, "Read(*)");
|
|
|
|
expect(result.all).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe("getPatternsForTool", () => {
|
|
it("should return patterns for specific tool", () => {
|
|
const index = buildPatternIndex([
|
|
"Bash(git:*)",
|
|
"Bash(npm:*)",
|
|
"Read(*)",
|
|
]);
|
|
|
|
const bashPatterns = getPatternsForTool(index, "Bash");
|
|
const readPatterns = getPatternsForTool(index, "Read");
|
|
const writePatterns = getPatternsForTool(index, "Write");
|
|
|
|
expect(bashPatterns).toHaveLength(2);
|
|
expect(readPatterns).toHaveLength(1);
|
|
expect(writePatterns).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("getRawPatterns", () => {
|
|
it("should return all raw pattern strings", () => {
|
|
const patterns = ["Bash(git:*)", "Read(*)"];
|
|
const index = buildPatternIndex(patterns);
|
|
|
|
const raw = getRawPatterns(index);
|
|
|
|
expect(raw).toEqual(patterns);
|
|
});
|
|
});
|
|
|
|
describe("mergeIndexes", () => {
|
|
it("should merge multiple indexes", () => {
|
|
const index1 = buildPatternIndex(["Bash(git:*)"]);
|
|
const index2 = buildPatternIndex(["Read(*)"]);
|
|
const index3 = buildPatternIndex(["Write(src/*)"]);
|
|
|
|
const merged = mergeIndexes(index1, index2, index3);
|
|
|
|
expect(merged.all).toHaveLength(3);
|
|
expect(getPatternsForTool(merged, "Bash")).toHaveLength(1);
|
|
expect(getPatternsForTool(merged, "Read")).toHaveLength(1);
|
|
expect(getPatternsForTool(merged, "Write")).toHaveLength(1);
|
|
});
|
|
|
|
it("should preserve duplicates from different indexes", () => {
|
|
const index1 = buildPatternIndex(["Bash(git:*)"]);
|
|
const index2 = buildPatternIndex(["Bash(git:*)"]);
|
|
|
|
const merged = mergeIndexes(index1, index2);
|
|
|
|
// Duplicates preserved (session might override global)
|
|
expect(merged.all).toHaveLength(2);
|
|
});
|
|
|
|
it("should handle empty indexes", () => {
|
|
const index1 = createPatternIndex();
|
|
const index2 = buildPatternIndex(["Read(*)"]);
|
|
|
|
const merged = mergeIndexes(index1, index2);
|
|
|
|
expect(merged.all).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe("getIndexStats", () => {
|
|
it("should return correct statistics", () => {
|
|
const index = buildPatternIndex([
|
|
"Bash(git:*)",
|
|
"Bash(npm:*)",
|
|
"Read(*)",
|
|
"Write(src/*)",
|
|
"Edit(*.ts)",
|
|
]);
|
|
|
|
const stats = getIndexStats(index);
|
|
|
|
expect(stats.total).toBe(5);
|
|
expect(stats.byTool["Bash"]).toBe(2);
|
|
expect(stats.byTool["Read"]).toBe(1);
|
|
expect(stats.byTool["Write"]).toBe(1);
|
|
expect(stats.byTool["Edit"]).toBe(1);
|
|
});
|
|
});
|
|
});
|