Files
magpie/tests/repo-scanner/scanner.test.ts
xiaofanluan 7cccacdc51 feat: add repository-wide code review with feature analysis
Implement full repository review mode that detects logical features/modules
and reviews them systematically with session persistence for pause/resume
capability.

Key additions:
- RepoScanner: scans codebase and estimates tokens/cost
- FeatureAnalyzer: AI-powered detection of logical modules
- FeaturePlanner: creates review execution plan
- StateManager: persists sessions for resume capability
- RepoOrchestrator: executes feature-by-feature reviews
- MarkdownReporter: generates review reports

New CLI options: --repo, --quick, --deep, --list-sessions, --session,
--export, --path, --ignore, --plan-only, --reanalyze

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 22:58:22 +08:00

60 lines
2.1 KiB
TypeScript

// tests/repo-scanner/scanner.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { RepoScanner } from '../../src/repo-scanner/scanner.js'
import * as fs from 'fs'
import * as path from 'path'
vi.mock('fs')
vi.mock('path')
describe('RepoScanner', () => {
beforeEach(() => {
vi.resetAllMocks()
})
it('should scan directory and return file list', async () => {
// Mock directory structure: /project/src/index.ts
vi.mocked(fs.readdirSync).mockImplementation((p) => {
if (String(p) === '/project') return ['src'] as any
if (String(p) === '/project/src') return ['index.ts', 'utils.ts'] as any
return [] as any
})
vi.mocked(fs.statSync).mockImplementation((p) => ({
isDirectory: () => String(p) === '/project/src',
isFile: () => String(p).endsWith('.ts'),
size: 1024
}) as any)
vi.mocked(fs.readFileSync).mockReturnValue('line1\nline2\nline3')
vi.mocked(path.join).mockImplementation((...args) => args.join('/'))
vi.mocked(path.relative).mockImplementation((from, to) => String(to).replace(from + '/', ''))
const scanner = new RepoScanner('/project')
const files = await scanner.scanFiles()
expect(files.length).toBe(2)
expect(files[0].relativePath).toBe('src/index.ts')
expect(files[0].language).toBe('typescript')
expect(files[0].lines).toBe(3)
})
it('should calculate repo stats', async () => {
const scanner = new RepoScanner('/project')
scanner['files'] = [
{ path: '/project/src/a.ts', relativePath: 'src/a.ts', language: 'typescript', lines: 100, size: 1024 },
{ path: '/project/src/b.ts', relativePath: 'src/b.ts', language: 'typescript', lines: 50, size: 512 }
]
const stats = scanner.getStats()
expect(stats.totalFiles).toBe(2)
expect(stats.totalLines).toBe(150)
expect(stats.languages.typescript).toBe(2)
})
it('should estimate tokens based on file content', () => {
const scanner = new RepoScanner('/project')
const tokens = scanner['estimateTokens'](1000) // 1000 characters
expect(tokens).toBe(250) // ~4 chars per token
})
})