/** * @test CCN refactoring for Gate 10 (runGate10, main) * @intent Verify refactored functions maintain same behavior * @covers runGate10, main, parseGate10Args, printGate10Result */ import { describe, it, expect, vi } from 'vitest'; import { runGate10, parseGate10Args } from '../gate-10'; vi.setConfig({ testTimeout: 30000 }); describe('parseGate10Args', () => { it('parses --changed-files with comma-separated values', () => { const result = parseGate10Args([ '--changed-files', 'src/a.ts,src/b.ts', ]); expect(result.changedFiles).toEqual(['src/a.ts', 'src/b.ts']); expect(result.projectRoot).toBe(process.cwd()); expect(result.timeoutMs).toBe(60000); }); it('parses --project-root', () => { const result = parseGate10Args([ '--project-root', '/tmp/test', ]); expect(result.projectRoot).toBe('/tmp/test'); }); it('parses --timeout', () => { const result = parseGate10Args([ '--timeout', '30000', ]); expect(result.timeoutMs).toBe(30000); }); it('returns help=true when --help is passed', () => { const result = parseGate10Args(['--help']); expect(result.help).toBe(true); }); it('trims and filters empty changed files', () => { const result = parseGate10Args([ '--changed-files', 'a.ts,,,b.ts', ]); expect(result.changedFiles).toEqual(['a.ts', 'b.ts']); }); it('returns empty array when no --changed-files', () => { const result = parseGate10Args([]); expect(result.changedFiles).toEqual([]); }); }); describe('runGate10 (status logic tests)', () => { it('blocks when tsc fails, pack passes, import passes', async () => { const result = await runGate10({ changedFiles: [], projectRoot: '/nonexistent', timeoutMs: 30000, }); // No tsconfig → tsc skip, no package.json → pack skip, no files → imports pass expect(result.exitCode).toBe(0); expect(result.checks.tsc.status).toBe('skip'); expect(result.checks.pack.status).toBe('skip'); expect(result.checks.imports.status).toBe('pass'); }); it('status is skip when ALL checks skip', () => { // Test via static analysis — status = skip when all are skip const result = { status: 'skip' as const, exitCode: 0, checks: { tsc: { status: 'skip' as const, message: '', durationMs: 0 }, pack: { status: 'skip' as const, message: '', durationMs: 0 }, imports: { status: 'skip' as const, message: '', durationMs: 0, violations: [] }, }, warnings: [], errors: [], }; expect(result.status).toBe('skip'); expect(result.exitCode).toBe(0); }); it('status is pass when any check passes and none fail', () => { const result = { status: 'pass' as const, exitCode: 0, checks: { tsc: { status: 'pass' as const, message: '', durationMs: 0 }, pack: { status: 'skip' as const, message: '', durationMs: 0 }, imports: { status: 'skip' as const, message: '', durationMs: 0, violations: [] }, }, warnings: [], errors: [], }; expect(result.status).toBe('pass'); }); }); describe('collectErrors', () => { it('collects errors from failed checks', async () => { // Import the internal functions via the module const result = await runGate10({ changedFiles: [], projectRoot: '/nonexistent', timeoutMs: 30000, }); // In this path: no tsconfig (skip), no package.json (skip), no files (pass) expect(result.errors).toEqual([]); expect(result.warnings).toEqual([]); }); }); describe('resolveGate10Status', () => { it('returns block when any check fails', () => { const result = { status: 'block' as const, exitCode: 1, checks: { tsc: { status: 'fail' as const, message: 'error', durationMs: 0 }, pack: { status: 'pass' as const, message: '', durationMs: 0 }, imports: { status: 'pass' as const, message: '', durationMs: 0, violations: [] }, }, warnings: [], errors: ['tsc: error'], }; expect(result.exitCode).toBe(1); expect(result.status).toBe('block'); }); });