92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
/**
|
|
* Tests for Claude client utilities
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
detectStatus,
|
|
isRegexSafe,
|
|
getBuiltinStatusPatterns,
|
|
} from '../claude/client.js';
|
|
|
|
describe('detectStatus', () => {
|
|
it('should detect done status', () => {
|
|
const content = 'Task completed successfully.\n[CODER:DONE]';
|
|
const patterns = { done: '\\[CODER:DONE\\]' };
|
|
expect(detectStatus(content, patterns)).toBe('done');
|
|
});
|
|
|
|
it('should detect approved status', () => {
|
|
const content = 'Code looks good.\n[ARCHITECT:APPROVE]';
|
|
const patterns = { approved: '\\[ARCHITECT:APPROVE\\]' };
|
|
expect(detectStatus(content, patterns)).toBe('approved');
|
|
});
|
|
|
|
it('should return in_progress when no pattern matches', () => {
|
|
const content = 'Working on it...';
|
|
const patterns = { done: '\\[DONE\\]' };
|
|
expect(detectStatus(content, patterns)).toBe('in_progress');
|
|
});
|
|
|
|
it('should be case insensitive', () => {
|
|
const content = '[coder:done]';
|
|
const patterns = { done: '\\[CODER:DONE\\]' };
|
|
expect(detectStatus(content, patterns)).toBe('done');
|
|
});
|
|
|
|
it('should handle invalid regex gracefully', () => {
|
|
const content = 'test';
|
|
const patterns = { done: '[invalid(' };
|
|
expect(detectStatus(content, patterns)).toBe('in_progress');
|
|
});
|
|
});
|
|
|
|
describe('isRegexSafe', () => {
|
|
it('should accept simple patterns', () => {
|
|
expect(isRegexSafe('\\[DONE\\]')).toBe(true);
|
|
expect(isRegexSafe('hello')).toBe(true);
|
|
expect(isRegexSafe('^start')).toBe(true);
|
|
});
|
|
|
|
it('should reject patterns that are too long', () => {
|
|
const longPattern = 'a'.repeat(201);
|
|
expect(isRegexSafe(longPattern)).toBe(false);
|
|
});
|
|
|
|
it('should reject ReDoS patterns', () => {
|
|
expect(isRegexSafe('(.*)*')).toBe(false);
|
|
expect(isRegexSafe('(.+)+')).toBe(false);
|
|
expect(isRegexSafe('(a|b)+')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getBuiltinStatusPatterns', () => {
|
|
it('should return patterns for coder', () => {
|
|
const patterns = getBuiltinStatusPatterns('coder');
|
|
expect(patterns.done).toBeDefined();
|
|
expect(patterns.blocked).toBeDefined();
|
|
});
|
|
|
|
it('should return patterns for architect', () => {
|
|
const patterns = getBuiltinStatusPatterns('architect');
|
|
expect(patterns.approved).toBeDefined();
|
|
expect(patterns.rejected).toBeDefined();
|
|
});
|
|
|
|
it('should return generic patterns for unknown agent', () => {
|
|
// With generic patterns, any agent gets the standard patterns
|
|
const patterns = getBuiltinStatusPatterns('unknown');
|
|
expect(patterns.approved).toBeDefined();
|
|
expect(patterns.rejected).toBeDefined();
|
|
expect(patterns.done).toBeDefined();
|
|
expect(patterns.blocked).toBeDefined();
|
|
});
|
|
|
|
it('should detect status using generic patterns for any agent', () => {
|
|
// Generic patterns work for any [ROLE:COMMAND] format
|
|
const patterns = getBuiltinStatusPatterns('my-custom-agent');
|
|
const content = '[MY_CUSTOM_AGENT:APPROVE]';
|
|
expect(detectStatus(content, patterns)).toBe('approved');
|
|
});
|
|
});
|