UNPKG

codebridge-ai

Version:

Complete fullstack AI coding platform with AST-based code integration and local LLM support. Now with comprehensive web technology support (HTML/CSS/JS) plus JavaScript, Python, Rust, and C++.

361 lines (314 loc) 10.8 kB
const CodeBridge = require('../code-bridge'); describe('LLM 호환성 테스트', () => { let processor; beforeEach(() => { processor = new CodeBridge(); }); const originalCode = ` class DataService { fetchData(id) { return fetch('/api/data/' + id); } } `; describe('다양한 LLM 출력 형식 처리', () => { describe('Claude 스타일', () => { test('기본 Claude 형식', () => { const claudeOutput = ` // 보안과 에러 처리를 개선했습니다 // @decorator retry(3) // @decorator validateInput async fetchData(id) { if (!id) throw new Error('ID is required'); try { const response = await fetch(\`/api/data/\${encodeURIComponent(id)}\`); if (!response.ok) throw new Error('Failed to fetch'); return await response.json(); } catch (error) { console.error('Fetch failed:', error); throw error; } } `; const result = processor.process(originalCode, claudeOutput, 'js'); expect(result).toContain('@retry'); expect(result).toContain('@validateInput'); expect(result).toContain('async fetchData'); }); test('Claude 코드 블록 내 스니펫', () => { const claudeWithCodeBlock = ` 다음은 개선된 메서드입니다: \`\`\`javascript // @access private // @decorator cache async fetchData(id) { return this.cachedFetch(id); } \`\`\` `; // 코드 블록 추출 시뮬레이션 const codeMatch = claudeWithCodeBlock.match(/```javascript\n([\s\S]*?)```/); if (codeMatch) { const extractedCode = codeMatch[1]; const result = processor.process(originalCode, extractedCode, 'js'); expect(result).toContain('@cache'); } }); }); describe('GPT-4 스타일', () => { test('콜론이 있는 명령어 형식', () => { const gpt4Output = ` // @decorator: memoize // @access: public // @returns: Promise<Data> async fetchData(id) { // Implementation with memoization return memoizedFetch(id); } `; // 콜론 제거 전처리 필요 const normalizedOutput = gpt4Output.replace(/@(\w+):\s*/g, '@$1 '); const result = processor.process(originalCode, normalizedOutput, 'js'); expect(result).toBeTruthy(); }); test('설명이 포함된 형식', () => { const gpt4Verbose = ` Here's an improved version with better error handling: // This method now includes retry logic // @decorator retry // @decorator log async fetchData(id) { // Validate input if (typeof id !== 'string') { throw new TypeError('ID must be a string'); } // Fetch with retry return await this.fetchWithRetry(id); } `; const result = processor.process(originalCode, gpt4Verbose, 'js'); expect(result).toContain('@retry'); expect(result).toContain('@log'); }); }); describe('Gemini 스타일', () => { test('블록 주석 명령어', () => { const geminiOutput = ` /* @decorator async */ /* @decorator timeout(5000) */ /* @access protected */ fetchData(id) { return this.timedFetch(id, 5000); } `; // 블록 주석을 라인 주석으로 변환 const normalizedOutput = geminiOutput.replace(/\/\*\s*@(\w+)\s*([^*]*)\*\//g, '// @$1 $2'); const result = processor.process(originalCode, normalizedOutput, 'js'); expect(result).toBeTruthy(); }); test('혼합 주석 스타일', () => { const geminiMixed = ` /** * Improved fetch method * @decorator cache */ // @access private /* @decorator validate */ async fetchData(id) { return await this.validatedFetch(id); } `; // JSDoc 스타일 처리 const result = processor.process(originalCode, geminiMixed, 'js'); expect(result).toBeTruthy(); }); }); }); describe('주석 명령어 변형 처리', () => { const testVariations = [ { name: '공백 변형', variations: [ '// @decorator cache', '// @decorator cache', '//\t@decorator\tcache', '// @decorator cache' ] }, { name: '대소문자 변형', variations: [ '// @decorator cache', '// @Decorator cache', '// @DECORATOR cache', '// @dEcOrAtOr cache' ] }, { name: '구분자 변형', variations: [ '// @decorator cache', '// @decorator: cache', '// @decorator = cache', '// @decorator -> cache' ] } ]; testVariations.forEach(({ name, variations }) => { test(`should handle ${name}`, () => { variations.forEach(variant => { const snippet = ` ${variant} fetchData(id) { return fetch(id); } `; // 정규화 처리 const normalized = snippet .replace(/@(\w+)[:\s=\->]+/g, '@$1 ') .toLowerCase(); expect(() => processor.process(originalCode, normalized, 'js')) .not.toThrow(); }); }); }); }); describe('부분 코드 vs 전체 코드', () => { test('메서드만 있는 스니펫', () => { const methodOnly = ` // @decorator async fetchData(id) { return this.asyncFetch(id); } `; const result = processor.process(originalCode, methodOnly, 'js'); expect(result).toContain('fetchData'); expect(result).toContain('@async'); }); test('클래스 전체 교체', () => { const fullClass = ` class DataService { constructor() { this.cache = new Map(); } // @decorator memoize fetchData(id) { if (this.cache.has(id)) { return this.cache.get(id); } return fetch('/api/data/' + id); } clearCache() { this.cache.clear(); } } `; const result = processor.process(originalCode, fullClass, 'js'); expect(result).toContain('constructor'); expect(result).toContain('clearCache'); }); test('여러 메서드 동시 수정', () => { const multipleMethodsOriginal = ` class Service { method1() { return 1; } method2() { return 2; } method3() { return 3; } } `; const multipleMethodsSnippet = ` // @decorator log method1() { return 10; } // @delete method2() { } // @rename calculate method3() { return 30; } `; const result = processor.process(multipleMethodsOriginal, multipleMethodsSnippet, 'js'); expect(result).toContain('@log'); expect(result).not.toContain('method2'); expect(result).toContain('calculate'); }); }); describe('언어별 LLM 패턴', () => { test('Python 스타일 스니펫 (참고용)', () => { const pythonStyle = ` # @decorator lru_cache(maxsize=100) # @type_hints str -> Dict[str, Any] def fetch_data(self, id: str) -> Dict[str, Any]: """Fetch data with caching""" return self._fetch_with_cache(id) `; // Python 프로세서가 구현되면 테스트 expect(pythonStyle).toContain('@decorator'); expect(pythonStyle).toContain('@type_hints'); }); test('Rust 스타일 스니펫 (참고용)', () => { const rustStyle = ` // @visibility pub // @attributes #[tokio::main] // @generic <T: Send + Sync> async fn fetch_data<T: Send + Sync>(&self, id: &str) -> Result<T, Error> { self.fetch_with_timeout(id).await } `; // Rust 프로세서가 구현되면 테스트 expect(rustStyle).toContain('@visibility'); expect(rustStyle).toContain('@attributes'); }); }); describe('오류 복구 및 유연성', () => { test('부분적으로 잘못된 명령어', () => { const partiallyInvalid = ` // @decorator valid // @invalid-command something // @access private fetchData(id) { return fetch(id); } `; // 유효한 명령어만 처리되어야 함 const result = processor.process(originalCode, partiallyInvalid, 'js'); expect(result).toContain('@valid'); }); test('중복 명령어 처리', () => { const duplicateCommands = ` // @decorator cache // @decorator cache // @decorator log fetchData(id) { return fetch(id); } `; const result = processor.process(originalCode, duplicateCommands, 'js'); // 중복 제거 확인 const cacheCount = (result.match(/@cache/g) || []).length; expect(cacheCount).toBe(1); }); test('비어있는 명령어 값', () => { const emptyValues = ` // @decorator // @access fetchData(id) { return fetch(id); } `; // 빈 값은 무시되거나 기본값 사용 expect(() => processor.process(originalCode, emptyValues, 'js')) .not.toThrow(); }); }); }); // LLM별 사용 가이드 생성 const generateLLMGuide = (llmName) => { const guides = { claude: { format: '// @command value', example: '// @decorator cache\n// @access private', tips: '주석은 메서드 바로 위에 작성하세요' }, gpt4: { format: '// @command value 또는 // @command: value', example: '// @decorator: async\n// @access: public', tips: '콜론은 선택사항입니다' }, gemini: { format: '/* @command value */ 또는 // @command value', example: '/* @decorator memoize */\n/* @access protected */', tips: '블록 주석도 지원됩니다' } }; return guides[llmName] || guides.claude; }; module.exports = { generateLLMGuide };