99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
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<MediaItem> = {}) {
|
||
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)
|
||
})
|
||
})
|