/** * bridgeLauncher — NotebookLM 로컬 백엔드 원클릭 실행/종료의 순수 로직 검증. * (터미널 생성·프로세스 kill 같은 부수효과는 VS Code/OS 의존이라 여기선 순수 함수만.) */ import * as path from 'path'; import { candidateProjectDirs, buildPortKillCommand } from '../src/features/datacollect/bridgeLauncher'; jest.mock('vscode', () => ({ workspace: { getConfiguration: jest.fn(), workspaceFolders: [] }, window: {}, }), { virtual: true }); describe('candidateProjectDirs — 프로젝트 자동 탐색 후보 순서', () => { it('설정값이 있으면 항상 1순위다', () => { const dirs = candidateProjectDirs('/custom/Datacollector', ['/ws/ConnectAI']); expect(dirs[0]).toBe('/custom/Datacollector'); }); it('워크스페이스 자신 → 부모의 형제 폴더(이름 후보들) 순으로 나열한다', () => { const dirs = candidateProjectDirs('', ['/proj/ConnectAI']); expect(dirs[0]).toBe('/proj/ConnectAI'); expect(dirs).toContain(path.join('/proj', 'Datacollector_MAC')); expect(dirs).toContain(path.join('/proj', 'Datacollector')); expect(dirs).toContain(path.join('/proj', 'Datacollect')); }); it('중복 경로는 한 번만 나온다', () => { const dirs = candidateProjectDirs('/proj/Datacollector_MAC', ['/proj/ConnectAI', '/proj/ConnectAI']); expect(dirs.filter(d => d === path.join('/proj', 'Datacollector_MAC')).length).toBe(1); expect(dirs.filter(d => d === '/proj/ConnectAI').length).toBe(1); }); it('설정값 공백/빈 문자열은 무시한다', () => { expect(candidateProjectDirs(' ', [])).toEqual([]); expect(candidateProjectDirs('', [])).toEqual([]); }); }); describe('buildPortKillCommand — OS 자동 감지 분기', () => { it('윈도우는 PowerShell Stop-Process 를 쓴다', () => { const cmd = buildPortKillCommand('win32', 3002); expect(cmd).toContain('powershell'); expect(cmd).toContain('-LocalPort 3002'); expect(cmd).toContain('Stop-Process'); }); it('맥/리눅스는 lsof + kill 을 쓴다', () => { for (const platform of ['darwin', 'linux'] as NodeJS.Platform[]) { const cmd = buildPortKillCommand(platform, 3002); expect(cmd).toContain('lsof -ti :3002'); expect(cmd).toContain('kill'); } }); it('포트 번호가 명령에 반영된다', () => { expect(buildPortKillCommand('win32', 4100)).toContain('4100'); expect(buildPortKillCommand('darwin', 4100)).toContain(':4100'); }); });