import { describe, expect, it } from 'vitest'; import { audioPath, extFromMime, formatDuration, formatLocalTime, makeId, mimeFromExt, notePath, } from '../src/core/naming'; const T = new Date('2026-09-27T11:15:03.000Z'); // 14:15:03 по Москве function seq(...values: number[]): () => number { return () => values.shift() ?? 0; } describe('test environment', () => { it('runs in UTC+3', () => { expect(T.getHours()).toBe(14); }); }); describe('makeId', () => { it('uses UTC time and 4 hex chars', () => { expect(makeId(T, () => 0)).toBe('20260927-111503-0000'); expect(makeId(T, seq(0.99, 0.5, 0.0625, 0.1))).toBe('20260927-111503-f811'); }); it('clamps random() === 1 to f', () => { expect(makeId(T, () => 1)).toBe('20260927-111503-ffff'); }); it('does not depend on the local date', () => { const lateEvening = new Date('2026-09-27T22:30:00.000Z'); // 01:30 28-го по Москве expect(makeId(lateEvening, () => 0)).toBe('20260927-223000-0000'); expect(notePath(lateEvening, 1)).toBe('voice/inbox/2026-09-28 01-30-00.md'); }); }); describe('extFromMime', () => { it.each([ ['audio/mp4', 'm4a'], ['audio/webm', 'webm'], ['audio/webm;codecs=opus', 'webm'], ['AUDIO/MP4', 'm4a'], ['audio/ogg; codecs=opus', 'ogg'], ['audio/x-foo', 'bin'], ['', 'bin'], ])('%s → %s', (mime, ext) => { expect(extFromMime(mime)).toBe(ext); }); }); describe('paths', () => { it('audioPath', () => { expect(audioPath('20260927-111503-0000', 'audio/mp4')).toBe('voice/source/20260927-111503-0000.m4a'); }); it('notePath uses local time and suffix from 2', () => { expect(notePath(T, 1)).toBe('voice/inbox/2026-09-27 14-15-03.md'); expect(notePath(T, 2)).toBe('voice/inbox/2026-09-27 14-15-03 (2).md'); expect(notePath(T, 3)).toBe('voice/inbox/2026-09-27 14-15-03 (3).md'); }); }); describe('formatting', () => { it.each([ [0, '0:00'], [47_000, '0:47'], [125_400, '2:05'], [-5, '0:00'], ])('formatDuration(%d) = %s', (ms, text) => { expect(formatDuration(ms)).toBe(text); }); it('formatLocalTime', () => { expect(formatLocalTime('2026-09-27T11:17:03.000Z')).toBe('14:17'); }); }); describe('mimeFromExt', () => { it.each([ ['m4a', 'audio/mp4'], ['M4A', 'audio/mp4'], ['webm', 'audio/webm'], ['ogg', 'audio/ogg'], ])('%s → %s', (ext, mime) => { expect(mimeFromExt(ext)).toBe(mime); }); it.each(['bin', 'mp3', '', 'md'])('%j → null', (ext) => { expect(mimeFromExt(ext)).toBeNull(); }); });