import { describe, it, expect } from 'vitest'; import { clampFrame, naturalSortFiles, naturalSortBy, IMAGE_QUAD_LABELS, frameLabel, } from './imageSequenceModel'; // A minimal File stand-in — we only ever read `.name`. Avoids relying on the DOM // File constructor under the `node` vitest env. function mkFile(name: string): File { return { name } as File; } describe('clampFrame', () => { it('returns an in-range index unchanged', () => { expect(clampFrame(0, 10)).toBe(0); expect(clampFrame(4, 10)).toBe(4); expect(clampFrame(9, 10)).toBe(9); }); it('clamps an over-range index down to count - 1', () => { expect(clampFrame(15, 10)).toBe(9); expect(clampFrame(10, 10)).toBe(9); }); it('clamps a negative index up to 0', () => { expect(clampFrame(-3, 10)).toBe(0); }); it('returns 0 for a NaN / non-finite index', () => { expect(clampFrame(NaN, 10)).toBe(0); // Infinity is non-finite → 0 per the contract (not the max index). expect(clampFrame(Infinity, 10)).toBe(0); }); it('returns 0 for an empty sequence (count 0)', () => { expect(clampFrame(0, 0)).toBe(0); expect(clampFrame(3, 0)).toBe(0); }); it('floors a fractional index', () => { expect(clampFrame(2.9, 10)).toBe(2); }); }); describe('naturalSortFiles', () => { it('orders frame names numerically (frame2 < frame10)', () => { const sorted = naturalSortFiles([ mkFile('f10.png'), mkFile('f2.png'), mkFile('f1.png'), ]); expect(sorted.map((f) => f.name)).toEqual(['f1.png', 'f2.png', 'f10.png']); }); it('returns a new array and does not mutate the input', () => { const input = [mkFile('b.png'), mkFile('a.png')]; const sorted = naturalSortFiles(input); expect(sorted).not.toBe(input); expect(input.map((f) => f.name)).toEqual(['b.png', 'a.png']); }); }); describe('naturalSortBy', () => { it('sorts by a string key with numeric awareness', () => { expect(naturalSortBy(['x10', 'x2', 'x1'], (s) => s)).toEqual(['x1', 'x2', 'x10']); }); }); describe('IMAGE_QUAD_LABELS', () => { it('carries the Vietnamese pane labels with diacritics', () => { expect(IMAGE_QUAD_LABELS[0]).toBe('Ảnh gốc'); expect(IMAGE_QUAD_LABELS[1]).toBe('Bản đồ độ sâu'); expect(IMAGE_QUAD_LABELS[2]).toBe('Phủ phân vùng'); expect(IMAGE_QUAD_LABELS[3]).toBe('Tái tạo 3D'); }); }); describe('frameLabel', () => { it('returns "khung 0/0" for an empty sequence', () => { expect(frameLabel(0, 0)).toBe('khung 0/0'); }); it('formats a 1-based counter', () => { expect(frameLabel(4, 10)).toBe('khung 5/10'); expect(frameLabel(0, 10)).toBe('khung 1/10'); }); it('clamps the index inside the counter', () => { expect(frameLabel(99, 10)).toBe('khung 10/10'); expect(frameLabel(-5, 10)).toBe('khung 1/10'); }); });