retrotoon-studio/server/videoProcessor.test.ts

81 lines
3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { computeHistogramDifference, compositeLayerOrder, selectBestReferenceFrame } from "./videoProcessor";
import type { CompositeLayer } from "./videoProcessor";
describe("videoProcessor", () => {
describe("computeHistogramDifference", () => {
it("returns 0 for identical histograms", () => {
const hist = [0.25, 0.25, 0.25, 0.25];
const diff = computeHistogramDifference(hist, hist);
expect(diff).toBe(0);
});
it("returns a positive value for different histograms", () => {
const histA = [0.5, 0.3, 0.1, 0.1];
const histB = [0.1, 0.1, 0.3, 0.5];
const diff = computeHistogramDifference(histA, histB);
expect(diff).toBeGreaterThan(0);
});
it("returns 1.0 for mismatched lengths", () => {
const histA = [0.5, 0.5];
const histB = [0.33, 0.33, 0.34];
const diff = computeHistogramDifference(histA, histB);
expect(diff).toBe(1.0);
});
it("is symmetric", () => {
const histA = [0.4, 0.3, 0.2, 0.1];
const histB = [0.1, 0.2, 0.3, 0.4];
expect(computeHistogramDifference(histA, histB)).toBe(computeHistogramDifference(histB, histA));
});
});
describe("compositeLayerOrder", () => {
it("filters invisible layers and sorts by order", () => {
const layers: CompositeLayer[] = [
{ imageUrl: "/a.png", opacity: 1, order: 3, visible: true },
{ imageUrl: "/b.png", opacity: 0.5, order: 1, visible: true },
{ imageUrl: "/c.png", opacity: 1, order: 2, visible: false },
];
const result = compositeLayerOrder(layers);
expect(result).toHaveLength(2);
expect(result[0].imageUrl).toBe("/b.png");
expect(result[1].imageUrl).toBe("/a.png");
});
it("returns empty array when all layers are invisible", () => {
const layers: CompositeLayer[] = [
{ imageUrl: "/a.png", opacity: 1, order: 1, visible: false },
];
expect(compositeLayerOrder(layers)).toHaveLength(0);
});
});
describe("selectBestReferenceFrame", () => {
it("selects the highest quality static frame", () => {
const analyses = [
{ frameIndex: 0, qualityScore: 60, isStaticBackground: true },
{ frameIndex: 10, qualityScore: 95, isStaticBackground: true },
{ frameIndex: 20, qualityScore: 80, isStaticBackground: false },
{ frameIndex: 30, qualityScore: 70, isStaticBackground: true },
];
const best = selectBestReferenceFrame(analyses);
expect(best).toBe(10);
});
it("falls back to first frame when no static backgrounds exist", () => {
const analyses = [
{ frameIndex: 5, qualityScore: 90, isStaticBackground: false },
{ frameIndex: 15, qualityScore: 85, isStaticBackground: false },
];
const best = selectBestReferenceFrame(analyses);
expect(best).toBe(5);
});
it("returns 0 for empty array", () => {
const best = selectBestReferenceFrame([]);
expect(best).toBe(0);
});
});
});