/** * Unit tests for the resolutionW/resolutionH promotion (METADATA_KEYS ยง3). * * Pure function over an already-built stream/* map - no FFprobe, no fixtures, * so these run everywhere (unlike integration.test.ts). */ import { describe, it, expect } from 'vitest'; import { promoteResolution, applyDisplayRotation, isQuarterTurn } from '../src/plugin.js'; const stream = (o: Record) => JSON.stringify(o); // Values as fluent-ffmpeg hands them over: positive degrees parse to a Number, // negative ones stay strings. describe('isQuarterTurn', () => { it.each([90, '-90', 270, '-270', '90.0'])('%s is a quarter turn', (r) => { expect(isQuarterTurn(r)).toBe(true); }); it.each([0, '-180', 180, undefined, '', 'N/A'])('%s is not', (r) => { expect(isQuarterTurn(r)).toBe(false); }); }); describe('applyDisplayRotation', () => { it('swaps coded dimensions to display dimensions on a quarter turn', () => { const s: Record = { type: 'video', width: 1920, height: 1080 }; applyDisplayRotation(s, '-90'); expect(s).toEqual({ type: 'video', width: 1080, height: 1920 }); }); it('leaves a half turn unswapped and drops the rotation field', () => { const s: Record = { width: 1920, height: 1080, rotation: -180 }; applyDisplayRotation(s); expect(s).toEqual({ width: 1920, height: 1080 }); }); it('moves a lone axis to the other side', () => { const s: Record = { height: 1080, rotation: 90 }; applyDisplayRotation(s); expect(s).toEqual({ width: 1080 }); }); }); describe('promoteResolution', () => { it('promotes the primary video stream dimensions', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'video', codec: 'h264', width: 1920, height: 1080 }), 'stream/1': stream({ type: 'audio', codec: 'eac3' }), }) ).toEqual({ resolutionW: '1920', resolutionH: '1080' }); }); it('uses the FIRST video stream, not a later one', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'audio', codec: 'aac' }), 'stream/1': stream({ type: 'video', width: 1280, height: 720 }), 'stream/2': stream({ type: 'video', width: 640, height: 480 }), }) ).toEqual({ resolutionW: '1280', resolutionH: '720' }); }); it('emits string values, never numbers (int-string format)', () => { const out = promoteResolution({ 'stream/0': stream({ type: 'video', width: 1920, height: 1080 }), }); expect(typeof out.resolutionW).toBe('string'); expect(typeof out.resolutionH).toBe('string'); }); it('writes each axis independently when one is missing', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'video', height: 1080 }) }) ).toEqual({ resolutionH: '1080' }); }); it('returns nothing when there is no video stream', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'audio', codec: 'flac' }), 'stream/1': stream({ type: 'subtitle', codec: 'subrip' }), }) ).toEqual({}); }); it('returns nothing when the video stream has no usable dimensions', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'video', width: 0, height: 0 }) }) ).toEqual({}); }); it('never overwrites values already on the record', () => { expect( promoteResolution( { 'stream/0': stream({ type: 'video', width: 1920, height: 1080 }) }, { resolutionW: '1440', resolutionH: '1080' } ) ).toEqual({}); }); it('backfills only the axis that is missing', () => { expect( promoteResolution( { 'stream/0': stream({ type: 'video', width: 1920, height: 1080 }) }, { resolutionH: '1080' } ) ).toEqual({ resolutionW: '1920' }); }); it('survives a malformed stream entry', () => { expect( promoteResolution({ 'stream/0': 'not json', 'stream/1': stream({ type: 'video', width: 3840, height: 2160 }), }) ).toEqual({ resolutionW: '3840', resolutionH: '2160' }); }); it('promotes display dimensions from a legacy stream that still carries rotation', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'video', width: 1920, height: 1080, rotation: '90' }), }) ).toEqual({ resolutionW: '1080', resolutionH: '1920' }); }); it('stops at the first gap in the stream index', () => { expect( promoteResolution({ 'stream/0': stream({ type: 'audio' }), 'stream/2': stream({ type: 'video', width: 1920, height: 1080 }), }) ).toEqual({}); }); });