/** * 계획 계약 검증기 테스트 */ import { validateGoalClarity, validateStepCompleteness, validateExecutability, validateRiskAssessment, validateVerifiability, validateTemporalConstraints, validateRollbackCapability, validateContract, createEpitaph } from './contract-validator'; import { Plan } from './types'; describe('계획 계약 검증기', () => { describe('조항 1: 목표 명확성', () => { it('명확한 목표는 통과해야 함', () => { const plan: Plan = { id: 'test-1', goal: { description: '테스트 파일 10개 생성', criteria: ['파일 10개 생성됨', '각 파일 크기 > 0'], produces: ['test-files'] }, steps: [] }; const result = validateGoalClarity(plan); expect(result.passed).toBe(true); expect(result.issues).toHaveLength(0); }); it('모호한 표현이 있으면 실패해야 함', () => { const plan: Plan = { id: 'test-2', goal: { description: '테스트 파일을 잘 생성', criteria: [] }, steps: [] }; const result = validateGoalClarity(plan); expect(result.passed).toBe(false); expect(result.issues.length).toBeGreaterThan(0); }); it('판단 기준이 없으면 실패해야 함', () => { const plan: Plan = { id: 'test-3', goal: { description: '파일 생성', criteria: [] }, steps: [] }; const result = validateGoalClarity(plan); expect(result.passed).toBe(false); expect(result.issues).toContain('목표 달성 판단 기준이 없음'); }); }); describe('조항 2: 단계 완전성', () => { it('올바른 의존성 순서는 통과해야 함', () => { const plan: Plan = { id: 'test-4', goal: { description: '빌드 완료', criteria: ['빌드 성공'], produces: ['build-output'] }, steps: [ { id: 'step1', description: '의존성 설치', produces: ['deps'] }, { id: 'step2', description: '컴파일', dependencies: ['step1'], produces: ['build-output'] } ] }; const result = validateStepCompleteness(plan); expect(result.passed).toBe(true); }); it('순서 위반이 있으면 실패해야 함', () => { const plan: Plan = { id: 'test-5', goal: { description: '빌드 완료', criteria: ['빌드 성공'] }, steps: [ { id: 'step1', description: '컴파일', dependencies: ['step2'] }, { id: 'step2', description: '의존성 설치' } ] }; const result = validateStepCompleteness(plan); expect(result.passed).toBe(false); }); }); describe('조항 3: 실행 가능성', () => { it('사용 가능한 명령어는 통과해야 함', () => { const plan: Plan = { id: 'test-6', goal: { description: '테스트', criteria: ['완료'] }, steps: [ { id: 'step1', command: 'npm', timeout: 30000 } ] }; const result = validateExecutability(plan, ['npm', 'node']); expect(result.passed).toBe(true); }); it('타임아웃 없으면 실패해야 함', () => { const plan: Plan = { id: 'test-7', goal: { description: '테스트', criteria: ['완료'] }, steps: [ { id: 'step1', command: 'npm' } ] }; const result = validateExecutability(plan, ['npm']); expect(result.passed).toBe(false); expect(result.issues).toContain('단계 step1: 타임아웃 미설정'); }); }); describe('조항 4: 리스크 평가', () => { it('리스크와 완화 전략이 있으면 통과해야 함', () => { const plan: Plan = { id: 'test-8', goal: { description: '배포', criteria: ['성공'] }, steps: [], risks: [ { id: 'risk1', description: '네트워크 오류', severity: 'medium', mitigation: '재시도 로직 구현' } ] }; const result = validateRiskAssessment(plan); expect(result.passed).toBe(true); }); it('고위험 리스크에 대안 경로 없으면 실패해야 함', () => { const plan: Plan = { id: 'test-9', goal: { description: '배포', criteria: ['성공'] }, steps: [], risks: [ { id: 'risk1', description: '데이터 손상', severity: 'critical' } ] }; const result = validateRiskAssessment(plan); expect(result.passed).toBe(false); }); }); describe('조항 5: 검증 가능성', () => { it('예상 결과와 어설션이 있으면 통과해야 함', () => { const plan: Plan = { id: 'test-10', goal: { description: '파일 생성', criteria: ['완료'] }, steps: [ { id: 'step1', description: '파일 생성', expectedOutcome: '파일이 생성됨', assertions: ['file.exists()'] } ] }; const result = validateVerifiability(plan); expect(result.passed).toBe(true); }); it('어설션 없으면 실패해야 함', () => { const plan: Plan = { id: 'test-11', goal: { description: '파일 생성', criteria: ['완료'] }, steps: [ { id: 'step1', description: '파일 생성', expectedOutcome: '파일이 생성됨' } ] }; const result = validateVerifiability(plan); expect(result.passed).toBe(false); }); }); describe('조항 6: 시간적 제약', () => { it('시간 제약이 설정되면 통과해야 함', () => { const plan: Plan = { id: 'test-12', goal: { description: '빌드', criteria: ['완료'] }, steps: [ { id: 'step1', timeout: 60000 } ], estimatedDuration: 120000, timeoutStrategy: '실패 후 롤백' }; const result = validateTemporalConstraints(plan); expect(result.passed).toBe(true); }); }); describe('조항 7: 롤백 가능성', () => { it('올바른 롤백 시퀀스가 있으면 통과해야 함', () => { const plan: Plan = { id: 'test-13', goal: { description: '배포', criteria: ['완료'] }, steps: [], rollbackCommands: [ { id: 'rb1', command: 'rollback-step2', order: 2, verification: 'check-state' }, { id: 'rb2', command: 'rollback-step1', order: 1, verification: 'check-state' } ] }; const result = validateRollbackCapability(plan); expect(result.passed).toBe(true); }); }); describe('전체 계약 검증', () => { it('모든 조항 충족 시 A 등급 부여', () => { const plan: Plan = { id: 'test-full', goal: { description: '완전한 테스트 계획', criteria: ['모든 단계 성공'], produces: ['result'] }, steps: [ { id: 'step1', description: '준비', command: 'prepare', timeout: 10000, expectedOutcome: '준비 완료', assertions: ['ready'], produces: ['prepared'] }, { id: 'step2', description: '실행', command: 'execute', dependencies: ['step1'], timeout: 30000, expectedOutcome: '실행 완료', assertions: ['completed'], produces: ['result'] } ], risks: [ { id: 'risk1', description: '실패 가능성', severity: 'low', mitigation: '재시도' } ], estimatedDuration: 60000, timeoutStrategy: '중단', rollbackCommands: [ { id: 'rb1', command: 'cleanup', order: 1, verification: 'check-clean' } ] }; const result = validateContract(plan, ['prepare', 'execute']); expect(result.grade).toBe('A'); }); }); describe('에피타이드 생성', () => { it('올바른 에피타이드를 생성해야 함', () => { const plan: Plan = { id: 'test-epitaph', goal: { description: '테스트', criteria: ['완료'] }, steps: [] }; const validation = validateContract(plan); const epitaph = createEpitaph(plan, validation, { status: 'success', duration: 5000 }); expect(epitaph.planId).toBe('test-epitaph'); expect(epitaph.timestamp).toBeDefined(); expect(epitaph.executionResult.status).toBe('success'); }); }); });