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>
25 lines
966 B
TypeScript
25 lines
966 B
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { buildTargetPath, withCollisionSuffix } from '../src/main/pathBuilder'
|
|
import type { CaptureDate } from '../src/shared/types'
|
|
|
|
const date: CaptureDate = { year: '2024', month: '03', source: 'exif' }
|
|
|
|
describe('buildTargetPath', () => {
|
|
it('인물 매칭 시 /프로필/YYYY/MM/파일명 경로를 만든다', () => {
|
|
const p = buildTargetPath('/out', 'seunghyun', date, '/src/a/photo.jpg')
|
|
expect(p.replace(/\\/g, '/')).toBe('/out/seunghyun/2024/03/photo.jpg')
|
|
})
|
|
|
|
it('미검출(who=null) 시 [미정] 폴더로 보낸다', () => {
|
|
const p = buildTargetPath('/out', null, date, '/src/photo.png')
|
|
expect(p.replace(/\\/g, '/')).toBe('/out/[미정]/2024/03/photo.png')
|
|
})
|
|
})
|
|
|
|
describe('withCollisionSuffix', () => {
|
|
it('확장자 앞에 _N을 붙인다', () => {
|
|
const p = withCollisionSuffix('/out/x/photo.jpg', 2)
|
|
expect(p.replace(/\\/g, '/')).toBe('/out/x/photo_2.jpg')
|
|
})
|
|
})
|