import assert from 'node:assert/strict' import test from 'node:test' import { createMediaBlockMarkdown, formatMediaFileSize, getGallerySelectionOrder, getMediaItemKind, getMediaPickerPreviewUrl, isMediaItemSelectableForTarget, isUploadFileAllowedForMediaTarget, resolveSelectedMediaItems, toggleMediaSelectionState } from '../lib/markdown-editor-media.js' test('미디어 파일 크기를 표시 문자열로 변환한다', () => { assert.equal(formatMediaFileSize(512), '512 B') assert.equal(formatMediaFileSize(1536), '2 KB') assert.equal(formatMediaFileSize(1024 * 1024 * 1.5), '1.5 MB') assert.equal(formatMediaFileSize(0), '') }) test('미디어 항목 kind가 없으면 확장자와 URL로 종류를 판별한다', () => { assert.equal(getMediaItemKind({ url: '/uploads/a.webp' }), 'image') assert.equal(getMediaItemKind({ url: '/uploads/a.mp4?x=1' }), 'video') assert.equal(getMediaItemKind({ url: '/uploads/a.m4a' }), 'audio') assert.equal(getMediaItemKind({ url: '/uploads/a.zip' }), 'file') }) test('선택 대상별로 허용 미디어를 판별하고 파생 썸네일은 제외한다', () => { assert.equal(isMediaItemSelectableForTarget({ url: '/uploads/posts/2026/07/a.png' }, 'image'), true) assert.equal(isMediaItemSelectableForTarget({ url: '/uploads/posts/2026/07/a.mp4' }, 'image'), false) assert.equal(isMediaItemSelectableForTarget({ url: '/uploads/posts/2026/07/a.mp4' }, 'video'), true) assert.equal(isMediaItemSelectableForTarget({ url: '/uploads/posts/2026/07/thumbs/a-card.webp' }, 'image'), false) assert.equal(isMediaItemSelectableForTarget({ url: '/uploads/posts/2026/07/thumbs/a-body-720.webp' }, 'gallery'), false) }) test('미디어 선택 미리보기는 본문 파생 썸네일을 우선한다', () => { assert.equal(getMediaPickerPreviewUrl({ url: '/uploads/posts/2026/07/a.png', updatedAt: '2026-07-24T00:00:00.000Z', size: 100, bodyThumbnailStatus: { hasThumbnail: true } }), '/uploads/posts/2026/07/thumbs/a-body-720.webp?v=2026-07-24T00%3A00%3A00.000Z-100') }) test('업로드 파일은 선택 대상별 MIME 타입으로 허용 여부를 판별한다', () => { assert.equal(isUploadFileAllowedForMediaTarget({ type: 'image/png' }, 'gallery'), true) assert.equal(isUploadFileAllowedForMediaTarget({ type: 'video/mp4' }, 'video'), true) assert.equal(isUploadFileAllowedForMediaTarget({ type: 'audio/mpeg' }, 'audio'), true) assert.equal(isUploadFileAllowedForMediaTarget({ type: 'application/pdf' }, 'file'), true) assert.equal(isUploadFileAllowedForMediaTarget({ type: 'image/png' }, 'file'), false) }) test('미디어 항목으로 fenced 미디어 블록을 만든다', () => { assert.deepEqual(createMediaBlockMarkdown('video', { url: '/uploads/a.mp4', title: '영상' }), [':::video', 'url=/uploads/a.mp4', 'title=영상', 'caption=', ':::']) assert.deepEqual(createMediaBlockMarkdown('file', { url: '/uploads/a.pdf', name: 'a.pdf', size: 2048 }), [':::file', 'url=/uploads/a.pdf', 'title=a.pdf', 'description=', 'name=a.pdf', 'size=2 KB', ':::']) }) test('갤러리 선택 순서를 선택 URL 순서로 반환한다', () => { assert.equal(getGallerySelectionOrder(['/a.png', '/b.png'], '/b.png'), 2) assert.equal(getGallerySelectionOrder(['/a.png'], '/b.png'), 0) }) test('단일 미디어 선택은 기존 선택을 새 항목 하나로 교체한다', () => { assert.deepEqual(toggleMediaSelectionState({ selectedUrls: ['/old.png'], selectedItemMap: { '/old.png': { url: '/old.png' } }, mediaItem: { url: '/new.png', name: 'new' }, isGallery: false }), { selectedUrls: ['/new.png'], selectedItemMap: { '/new.png': { url: '/new.png', name: 'new' } } }) }) test('갤러리 미디어 선택은 선택 추가와 제거를 토글한다', () => { const selected = toggleMediaSelectionState({ selectedUrls: ['/a.png'], selectedItemMap: { '/a.png': { url: '/a.png' } }, mediaItem: { url: '/b.png' }, isGallery: true }) assert.deepEqual(selected.selectedUrls, ['/a.png', '/b.png']) assert.deepEqual(Object.keys(selected.selectedItemMap), ['/a.png', '/b.png']) assert.deepEqual(toggleMediaSelectionState({ selectedUrls: selected.selectedUrls, selectedItemMap: selected.selectedItemMap, mediaItem: { url: '/a.png' }, isGallery: true }), { selectedUrls: ['/b.png'], selectedItemMap: { '/b.png': { url: '/b.png' } } }) }) test('선택된 URL 순서대로 미디어 항목을 해석한다', () => { assert.deepEqual(resolveSelectedMediaItems( ['/a.png', '/b.png', '/missing.png'], { '/a.png': { url: '/a.png', source: 'map' } }, [ { url: '/b.png', source: 'list' } ] ), [ { url: '/a.png', source: 'map' }, { url: '/b.png', source: 'list' } ]) })