8a8c10248c
Local-first photo organizer that auto-sorts images by face recognition and EXIF capture date. - Electron app with 3-process split: Main (Node) / UI Renderer (React) / hidden Inference Renderer (face-api + WebGL) - Core pipeline: scan -> face match + EXIF -> path build -> atomic move/copy - Move = copy -> verify -> delete; auto-rename on filename collision - 1st-registered profile = move, others = copy; unmatched -> [미정]/YYYY/MM - EXIF date with mtime fallback - Vitest unit tests (pathBuilder / fileOps / concurrency) all green - electron-builder config for Windows (nsis) + macOS (dmg) - Docs: PRD / DECISIONS / ARCHITECTURE Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
846 B
TypeScript
30 lines
846 B
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { createLimiter } from '../src/main/concurrency'
|
|
|
|
describe('createLimiter', () => {
|
|
it('동시 실행 수가 limit을 넘지 않는다', async () => {
|
|
const limit = createLimiter(2)
|
|
let active = 0
|
|
let maxActive = 0
|
|
|
|
const task = () =>
|
|
limit(async () => {
|
|
active++
|
|
maxActive = Math.max(maxActive, active)
|
|
await new Promise((r) => setTimeout(r, 10))
|
|
active--
|
|
})
|
|
|
|
await Promise.all(Array.from({ length: 10 }, task))
|
|
expect(maxActive).toBeLessThanOrEqual(2)
|
|
})
|
|
|
|
it('모든 작업의 결과를 반환한다', async () => {
|
|
const limit = createLimiter(3)
|
|
const results = await Promise.all(
|
|
Array.from({ length: 5 }, (_, i) => limit(async () => i * 2))
|
|
)
|
|
expect(results).toEqual([0, 2, 4, 6, 8])
|
|
})
|
|
})
|