feat: publish av-tools 0.1.0
This commit is contained in:
86
tests/unit/media/duration-timecode.test.ts
Normal file
86
tests/unit/media/duration-timecode.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
addDurations,
|
||||
clampTime,
|
||||
roundSeconds,
|
||||
validateSourceRange,
|
||||
} from '../../../src/media/duration';
|
||||
import {
|
||||
formatFrameTimecode,
|
||||
formatTimecode,
|
||||
parseTimecode,
|
||||
parseTimecodeDetailed,
|
||||
} from '../../../src/media/timecode';
|
||||
|
||||
describe('duration arithmetic', () => {
|
||||
it('adds durations without exposing common binary drift', () => {
|
||||
expect(addDurations([0.1, 0.2, 1.0000004])).toBe(1.3);
|
||||
expect(roundSeconds(-0.0000001, 3)).toBe(0);
|
||||
});
|
||||
|
||||
it('rejects invalid durations and clamps preview times', () => {
|
||||
expect(() => addDurations([1, Number.NaN])).toThrow();
|
||||
expect(() => addDurations([-1])).toThrow();
|
||||
expect(clampTime(-2, 10)).toBe(0);
|
||||
expect(clampTime(12, 10)).toBe(10);
|
||||
});
|
||||
|
||||
it('validates source in/out ranges and source bounds', () => {
|
||||
expect(validateSourceRange(1, 3, 5)).toEqual({
|
||||
valid: true,
|
||||
durationSeconds: 2,
|
||||
issues: [],
|
||||
});
|
||||
expect(validateSourceRange(3, 1, 5).issues[0]?.code).toBe(
|
||||
'source-out-before-in'
|
||||
);
|
||||
expect(validateSourceRange(1, 1, 5).issues[0]?.code).toBe('clip-too-short');
|
||||
expect(
|
||||
validateSourceRange(1, 6, 5).issues.some(
|
||||
(issue) => issue.code === 'source-out-after-duration'
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('timecode parsing and formatting', () => {
|
||||
it.each([
|
||||
['12.5', 12.5, undefined],
|
||||
['01:02.500', 62.5, undefined],
|
||||
['02:03:04.125', 7_384.125, undefined],
|
||||
['00:00:10:12', 10.5, { frameRate: 24 }],
|
||||
])('parses %s', (text, expected, options) => {
|
||||
expect(parseTimecode(text, options)).toBe(expected);
|
||||
});
|
||||
|
||||
it('reports malformed components', () => {
|
||||
expect(parseTimecodeDetailed('01:60')).toEqual({
|
||||
ok: false,
|
||||
reason: 'seconds-out-of-range',
|
||||
});
|
||||
expect(parseTimecodeDetailed('00:00:01:10')).toEqual({
|
||||
ok: false,
|
||||
reason: 'frame-rate-required',
|
||||
});
|
||||
expect(parseTimecodeDetailed('-00:01', { allowNegative: false })).toEqual({
|
||||
ok: false,
|
||||
reason: 'negative-not-allowed',
|
||||
});
|
||||
expect(parseTimecode('anything')).toBeUndefined();
|
||||
expect(parseTimecode('1.5:02:03')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('formats carry, precision, negative values and nominal frames', () => {
|
||||
expect(formatTimecode(59.9996)).toBe('00:01:00.000');
|
||||
expect(
|
||||
formatTimecode(62.5, {
|
||||
decimalPlaces: 2,
|
||||
alwaysShowHours: false,
|
||||
})
|
||||
).toBe('01:02.50');
|
||||
expect(formatTimecode(-1.25, { decimalPlaces: 2 })).toBe('-00:00:01.25');
|
||||
expect(formatFrameTimecode(10.5, 24)).toBe('00:00:10:12');
|
||||
expect(() => formatFrameTimecode(5, 0.5)).toThrow();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user