import { describe, expect, it } from 'vitest'; import { courseMaterialFingerprint, dedupeCourseMaterialFiles, } from '@/lib/document/course-materials'; import type { SelectedCourseMaterial } from '@/lib/types/generation'; function fileOf(name: string, content: string, lastModified: number): File { return new File([content], name, { type: 'text/plain', lastModified }); } function material(file: File, id: string): SelectedCourseMaterial { return { id, file, name: file.name, size: file.size, lastModified: file.lastModified, type: file.type, order: 1, }; } describe('courseMaterialFingerprint', () => { it('is stable for the same name, size, and lastModified', () => { const a = fileOf('lesson.pdf', 'same bytes', 1_700_000_000_000); const b = fileOf('lesson.pdf', 'same bytes', 1_700_000_000_000); expect(courseMaterialFingerprint(a)).toBe(courseMaterialFingerprint(b)); }); it('changes when the name changes', () => { expect(courseMaterialFingerprint(fileOf('a.pdf', 'x', 1000))).not.toBe( courseMaterialFingerprint(fileOf('b.pdf', 'x', 1000)), ); }); it('changes when the size changes', () => { expect(courseMaterialFingerprint(fileOf('a.pdf', 'x', 1000))).not.toBe( courseMaterialFingerprint(fileOf('a.pdf', 'xy', 1000)), ); }); it('changes when lastModified changes', () => { expect(courseMaterialFingerprint(fileOf('a.pdf', 'x', 1000))).not.toBe( courseMaterialFingerprint(fileOf('a.pdf', 'x', 1001)), ); }); it('also fingerprints an existing SelectedCourseMaterial by the same fields', () => { const file = fileOf('a.pdf', 'x', 1000); expect(courseMaterialFingerprint(material(file, 'm1'))).toBe(courseMaterialFingerprint(file)); }); }); describe('dedupeCourseMaterialFiles', () => { it('drops incoming files already present in the existing list', () => { const existing = fileOf('a.pdf', 'x', 1000); const incoming = fileOf('a.pdf', 'x', 1000); expect(dedupeCourseMaterialFiles([material(existing, 'm1')], [incoming])).toEqual([]); }); it('drops duplicates within a single incoming batch', () => { const one = fileOf('a.pdf', 'x', 1000); const two = fileOf('a.pdf', 'x', 1000); const other = fileOf('b.pdf', 'y', 2000); expect(dedupeCourseMaterialFiles([], [one, two, other])).toEqual([one, other]); }); it('keeps distinct files even when only one field differs', () => { const one = fileOf('a.pdf', 'x', 1000); const two = fileOf('a.pdf', 'x', 1001); expect(dedupeCourseMaterialFiles([], [one, two])).toEqual([one, two]); }); });