Files
metamesh-plugin-ffmpeg/test/promote-resolution.test.ts
Worph 1b194bf965
Build and Push Docker Image / build (push) Failing after 18s
fix resolution
2026-09-12 21:35:44 +02:00

137 lines
5.0 KiB
TypeScript

/**
* 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<string, unknown>) => 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<string, unknown> = { 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<string, unknown> = { 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<string, unknown> = { 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({});
});
});