import { describe, expect, it } from 'vitest' import type { MediaItem } from '@/composables/useMedia' import { groupDuplicates, mergeArticleCount } from '../mediaDuplicates' function copy(id: number, usedIn: number, createdAt: string, overrides: Partial = {}) { return { id, filename: `copy-${id}.jpg`, url: `/media/copy-${id}.jpg`, size: 2516582, content_type: 'image/jpeg', width: 3600, height: 2400, sha256: 'aa', uploaded_by: 'Inès Duarte', created_at: createdAt, used_in: usedIn, duplicate: true, ...overrides, } satisfies MediaItem } describe('groupDuplicates', () => { it.each([ [ 'the most used copy', [ copy(1, 4, '2026-06-14T12:00:00Z'), copy(2, 3, '2026-09-02T12:00:00Z'), copy(3, 2, '2026-08-30T12:00:00Z'), ], 1, ], [ 'the oldest copy at equal use', [copy(1, 2, '2026-08-29T12:00:00Z'), copy(2, 2, '2026-08-21T12:00:00Z')], 2, ], [ 'the oldest unused copy', [copy(1, 0, '2026-09-03T12:00:00Z'), copy(2, 0, '2026-09-01T12:00:00Z')], 2, ], [ 'the lowest id at equal use and date', [copy(9, 1, '2026-09-03T12:00:00Z'), copy(4, 1, '2026-09-03T12:00:00Z')], 4, ], ])('suggests %s', (_name, copies, suggestedId) => { const [group] = groupDuplicates(copies) expect(group!.suggested.id).toBe(suggestedId) expect(group!.copies[0]!.id).toBe(suggestedId) }) it('groups by sha256, orders copies and puts the oldest suggested copy first', () => { const groups = groupDuplicates([ copy(7, 2, '2026-08-29T12:00:00Z', { sha256: 'bb', size: 3250585 }), copy(5, 3, '2026-09-02T12:00:00Z'), copy(9, 1, '2026-08-21T12:00:00Z', { sha256: 'bb', size: 3250585 }), copy(12, 4, '2026-06-14T12:00:00Z'), copy(6, 2, '2026-08-30T12:00:00Z'), ]) expect(groups.map((group) => group.copies.map((item) => item.id))).toEqual([ [12, 5, 6], [7, 9], ]) expect(groups.map((group) => group.header)).toEqual([ '3 identical images · 2.4 MB each · 3600 × 2400', '2 identical images · 3.1 MB each · 3600 × 2400', ]) }) it('reads Vector for SVG groups and ignores single copies', () => { const groups = groupDuplicates([ copy(1, 0, '2026-09-01T12:00:00Z', { width: null, height: null, size: 8192 }), copy(2, 0, '2026-09-02T12:00:00Z', { width: null, height: null, size: 8192 }), copy(3, 0, '2026-09-02T12:00:00Z', { sha256: 'zz' }), ]) expect(groups).toHaveLength(1) expect(groups[0]!.header).toBe('2 identical images · 8 KB each · Vector') }) }) describe('mergeArticleCount', () => { it('sums the use of every copy except the kept one', () => { const copies = [ copy(12, 4, '2026-06-14T12:00:00Z'), copy(5, 3, '2026-09-02T12:00:00Z'), copy(6, 2, '2026-08-30T12:00:00Z'), ] expect(mergeArticleCount(copies, 12)).toBe(5) expect(mergeArticleCount(copies, 6)).toBe(7) }) })