import { describe, it, expect } from 'vitest' import { AssetManager } from '@/lib/assets/assetManager' function buf(bytes: number[]): Uint8Array { return new Uint8Array(bytes) } describe('AssetManager', () => { it('업로드 이미지를 해시하여 assets/.로 관리하고 중복을 제거한다', async () => { const am = new AssetManager({ maxBytes: 10 * 1024 * 1024, allowedExts: ['png', 'jpg', 'jpeg', 'webp', 'svg'], }) const a1 = await am.add({ name: 'hero.png', type: 'image/png', bytes: buf([1,2,3,4]) }) const a2 = await am.add({ name: 'another.png', type: 'image/png', bytes: buf([1,2,3,4]) }) const a3 = await am.add({ name: 'logo.svg', type: 'image/svg+xml', bytes: buf([60,115,118,103,62]) }) expect(a1.path).toMatch(/^assets\/[a-f0-9]{8}\.png$/) expect(a2.path).toBe(a1.path) // 동일 바이트 -> 동일 해시 -> 중복 제거 expect(a3.path).toMatch(/^assets\/[a-f0-9]{8}\.svg$/) const list = am.list() expect(list.length).toBe(2) const zipStruct = am.toZipStructure() const keys = Object.keys(zipStruct) expect(keys).toContain(a1.path) expect(keys).toContain(a3.path) expect(zipStruct[a1.path]).toBeInstanceOf(Uint8Array) }) it('허용되지 않은 확장자/크기는 거절한다', async () => { const am = new AssetManager({ maxBytes: 5, allowedExts: ['png'] }) await expect( am.add({ name: 'bad.gif', type: 'image/gif', bytes: buf([1]) }) ).rejects.toThrow(/extension/i) await expect( am.add({ name: 'big.png', type: 'image/png', bytes: buf([1,2,3,4,5,6]) }) ).rejects.toThrow(/size/i) }) it('rewriteUrl: http/https는 그대로, local:은 assets 경로로 치환한다', async () => { const am = new AssetManager({ maxBytes: 1024, allowedExts: ['png'] }) const external = am.rewriteUrl('https://cdn.example.com/x.png') expect(external).toBe('https://cdn.example.com/x.png') const ref = await am.add({ name: 'pic.png', type: 'image/png', bytes: buf([9,9,9]) }) const rewritten = am.rewriteUrl(`local:${ref.originalName}`) expect(rewritten).toBe(ref.path) }) })