claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
376 lines (298 loc) • 11.5 kB
text/typescript
import { getErrorMessage } from '../utils/error-handler.js';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
import { PromptCopier, copyPrompts } from '../prompt-copier.js';
import { EnhancedPromptCopier, copyPromptsEnhanced } from '../prompt-copier-enhanced.js';
import { PromptConfigManager, PromptValidator } from '../prompt-utils.js';
describe('PromptCopier', () => {
let tempDir: string;
let sourceDir: string;
let destDir: string;
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'prompt-test-'));
sourceDir = path.join(tempDir, 'source');
destDir = path.join(tempDir, 'dest');
await fs.mkdir(sourceDir, { recursive: true });
await fs.mkdir(destDir, { recursive: true });
// Create test files
await createTestFiles();
});
afterEach(async () => {
await fs.rm(tempDir, { recursive: true, force: true });
});
async function createTestFiles() {
const testFiles = [
{ path: 'test1.md', content: '# Test Prompt 1\nThis is a test prompt.' },
{ path: 'test2.txt', content: 'Test prompt content' },
{ path: 'subdir/test3.md', content: '## Nested Prompt\nNested content' },
{ path: 'large.md', content: 'Large content\n'.repeat(1000) },
{ path: 'empty.md', content: '' },
{ path: 'rules.md', content: '# Rules\nYou are an AI assistant.' },
];
for (const file of testFiles) {
const filePath = path.join(sourceDir, file.path);
const dir = path.dirname(filePath);
await fs.mkdir(dir, { recursive: true });
await fs.writeFile(filePath, file.content);
}
}
describe('Basic copying functionality', () => {
test('should copy all matching files', async () => {
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
});
expect(result.success).toBe(true);
expect(result.copiedFiles).toBe(6);
expect(result.failedFiles).toBe(0);
// Verify files exist
const destFiles = await fs.readdir(destDir, { recursive: true });
expect(destFiles).toHaveLength(6);
});
test('should respect include patterns', async () => {
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
includePatterns: ['*.md'],
});
expect(result.success).toBe(true);
expect(result.copiedFiles).toBe(5); // Only .md files
});
test('should respect exclude patterns', async () => {
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
excludePatterns: ['**/subdir/**'],
});
expect(result.success).toBe(true);
expect(result.copiedFiles).toBe(5); // Excluding subdir files
});
});
describe('Conflict resolution', () => {
test('should skip existing files when conflict resolution is skip', async () => {
// Create existing file
await fs.writeFile(path.join(destDir, 'test1.md'), 'Existing content');
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
conflictResolution: 'skip',
});
expect(result.success).toBe(true);
expect(result.skippedFiles).toBeGreaterThan(0);
// Verify original content preserved
const content = await fs.readFile(path.join(destDir, 'test1.md'), 'utf-8');
expect(content).toBe('Existing content');
});
test('should backup existing files when conflict resolution is backup', async () => {
// Create existing file
await fs.writeFile(path.join(destDir, 'test1.md'), 'Existing content');
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
conflictResolution: 'backup',
});
expect(result.success).toBe(true);
expect(result.backupLocation).toBeDefined();
// Verify backup directory exists
const backupDir = path.join(destDir, '.prompt-backups');
const backupExists = await fs
.access(backupDir)
.then(() => true)
.catch(() => false);
expect(backupExists).toBe(true);
});
test('should merge files when conflict resolution is merge', async () => {
// Create existing file
await fs.writeFile(path.join(destDir, 'test1.md'), 'Existing content');
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
conflictResolution: 'merge',
});
expect(result.success).toBe(true);
// Verify merged content
const content = await fs.readFile(path.join(destDir, 'test1.md'), 'utf-8');
expect(content).toContain('Existing content');
expect(content).toContain('MERGED CONTENT');
expect(content).toContain('# Test Prompt 1');
});
});
describe('Verification', () => {
test('should verify copied files when verification is enabled', async () => {
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
verify: true,
});
expect(result.success).toBe(true);
expect(result.failedFiles).toBe(0);
});
test('should detect verification failures', async () => {
// Mock fs.stat to simulate size mismatch
const originalStat = fs.stat;
jest.spyOn(fs, 'stat').mockImplementation(async (filePath: any) => {
const stats = await originalStat(filePath);
if (filePath.includes('dest') && filePath.includes('test1.md')) {
return { ...stats, size: stats.size + 1 };
}
return stats;
});
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
verify: true,
});
expect(result.errors.length).toBeGreaterThan(0);
expect(result.errors[0].phase).toBe('verify');
(fs.stat as jest.Mock).mockRestore();
});
});
describe('Dry run mode', () => {
test('should not create files in dry run mode', async () => {
const result = await copyPrompts({
source: sourceDir,
destination: destDir,
dryRun: true,
});
expect(result.success).toBe(true);
expect(result.totalFiles).toBe(6);
// Verify no files were actually copied
const destFiles = await fs.readdir(destDir);
expect(destFiles).toHaveLength(0);
});
});
describe('Progress reporting', () => {
test('should report progress during copy', async () => {
const progressUpdates: any[] = [];
await copyPrompts({
source: sourceDir,
destination: destDir,
progressCallback: (progress) => {
progressUpdates.push(progress);
},
});
expect(progressUpdates.length).toBeGreaterThan(0);
expect(progressUpdates[progressUpdates.length - 1].percentage).toBe(100);
});
});
});
describe('EnhancedPromptCopier', () => {
let tempDir: string;
let sourceDir: string;
let destDir: string;
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'enhanced-test-'));
sourceDir = path.join(tempDir, 'source');
destDir = path.join(tempDir, 'dest');
await fs.mkdir(sourceDir, { recursive: true });
await fs.mkdir(destDir, { recursive: true });
// Create test files
for (let i = 0; i < 20; i++) {
await fs.writeFile(path.join(sourceDir, `test${i}.md`), `# Test ${i}\nContent for test ${i}`);
}
});
afterEach(async () => {
await fs.rm(tempDir, { recursive: true, force: true });
});
test('should copy files using worker threads', async () => {
const result = await copyPromptsEnhanced({
source: sourceDir,
destination: destDir,
parallel: true,
maxWorkers: 4,
});
expect(result.success).toBe(true);
expect(result.copiedFiles).toBe(20);
expect(result.failedFiles).toBe(0);
// Verify all files were copied
const destFiles = await fs.readdir(destDir);
expect(destFiles).toHaveLength(20);
}, 10000);
});
describe('PromptConfigManager', () => {
let tempDir: string;
let configPath: string;
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'config-test-'));
configPath = path.join(tempDir, '.prompt-config.json');
});
afterEach(async () => {
await fs.rm(tempDir, { recursive: true, force: true });
});
test('should load default config when file does not exist', async () => {
const manager = new PromptConfigManager(configPath);
const config = await manager.loadConfig();
expect(config).toBeDefined();
expect(config.defaultOptions).toBeDefined();
expect(config.profiles).toBeDefined();
});
test('should save and load custom config', async () => {
const manager = new PromptConfigManager(configPath);
await manager.saveConfig({
destinationDirectory: './custom-prompts',
});
const config = await manager.loadConfig();
expect(config.destinationDirectory).toBe('./custom-prompts');
});
test('should get profile options', async () => {
const manager = new PromptConfigManager(configPath);
await manager.loadConfig();
const sparcProfile = manager.getProfile('sparc');
expect(sparcProfile).toBeDefined();
expect(sparcProfile.includePatterns).toContain('*.md');
});
test('should list available profiles', async () => {
const manager = new PromptConfigManager(configPath);
await manager.loadConfig();
const profiles = manager.listProfiles();
expect(profiles).toContain('sparc');
expect(profiles).toContain('templates');
expect(profiles).toContain('safe');
expect(profiles).toContain('fast');
});
});
describe('PromptValidator', () => {
let tempDir: string;
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'validator-test-'));
});
afterEach(async () => {
await fs.rm(tempDir, { recursive: true, force: true });
});
test('should validate valid prompt file', async () => {
const filePath = path.join(tempDir, 'valid.md');
await fs.writeFile(filePath, '# Test Prompt\nYou are an AI assistant.');
const result = await PromptValidator.validatePromptFile(filePath);
expect(result.valid).toBe(true);
expect(result.issues).toHaveLength(0);
});
test('should detect empty files', async () => {
const filePath = path.join(tempDir, 'empty.md');
await fs.writeFile(filePath, '');
const result = await PromptValidator.validatePromptFile(filePath);
expect(result.valid).toBe(false);
expect(result.issues).toContain('File is empty');
});
test('should extract front matter metadata', async () => {
const filePath = path.join(tempDir, 'with-metadata.md');
const content = `---
title: Test Prompt
version: 1.0
---
# Test Prompt
Content here`;
await fs.writeFile(filePath, content);
const result = await PromptValidator.validatePromptFile(filePath);
expect(result.metadata).toBeDefined();
expect(result.metadata.title).toBe('Test Prompt');
expect(result.metadata.version).toBe('1.0');
});
test('should warn about large files', async () => {
const filePath = path.join(tempDir, 'large.md');
const largeContent = '# Large Prompt\n' + 'x'.repeat(200 * 1024); // 200KB
await fs.writeFile(filePath, largeContent);
const result = await PromptValidator.validatePromptFile(filePath);
expect(result.issues).toContain('File is unusually large for a prompt');
});
});