import { appendFileSync, mkdtempSync, unlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; const { mockedExecFile, mockedExecFileAsync } = vi.hoisted(() => { const mockedExecFileAsync = vi.fn(); const mockedExecFile = vi.fn(); mockedExecFile[Symbol.for("nodejs.util.promisify.custom")] = mockedExecFileAsync; return { mockedExecFile, mockedExecFileAsync }; }); vi.mock("node:child_process", () => ({ execFile: mockedExecFile })); import { evaluateDeliveryConformance, getExportTools, parseRationalRate, validateDeliveryConformanceContract, } from "../../src/tools/export.js"; const probe = { format: { format_name: "mov,mp4,m4a", duration: "10.020", bit_rate: "12000000" }, streams: [ { codec_type: "video", codec_name: "h264", width: 1920, height: 1080, avg_frame_rate: "30000/1001", bit_rate: "10000000" }, { codec_type: "audio", codec_name: "aac", sample_rate: "48000", channels: 2 }, ], }; describe("delivery conformance comparisons", () => { it("parses rational frame rates and rejects malformed contracts", () => { expect(parseRationalRate("30000/1001")).toBeCloseTo(29.97003, 5); expect(parseRationalRate("0/0")).toBeNull(); expect(parseRationalRate("0/1")).toBeNull(); expect(parseRationalRate(0)).toBeNull(); expect(validateDeliveryConformanceContract({})).toContain("At least one"); expect(validateDeliveryConformanceContract({ width: -1 })).toContain("positive integer"); expect(validateDeliveryConformanceContract({ minimumVideoBitrateKbps: 20, maximumVideoBitrateKbps: 10 })).toContain("cannot exceed"); expect(parseRationalRate(24)).toBe(24); expect(parseRationalRate("bad")).toBeNull(); expect(validateDeliveryConformanceContract({ allowedContainerNames: [] })).toContain("container name"); expect(validateDeliveryConformanceContract({ audioChannels: 1.5 })).toContain("positive integer"); expect(validateDeliveryConformanceContract({ durationSeconds: 0 })).toContain("greater than 0"); expect(validateDeliveryConformanceContract({ durationToleranceSeconds: -1 })).toContain("non-negative"); expect(validateDeliveryConformanceContract({ targetLufs: 1 })).toContain("target_lufs"); expect(validateDeliveryConformanceContract({ maximumTruePeakDbfs: 1 })).toContain("maximum_true_peak"); expect(validateDeliveryConformanceContract({ frameRateTolerance: 0.01 })).toContain("frame_rate_tolerance requires frame_rate"); expect(validateDeliveryConformanceContract({ durationToleranceSeconds: 0.01 })).toContain("duration_tolerance_seconds requires duration_seconds"); expect(validateDeliveryConformanceContract({ loudnessToleranceLu: 1 })).toContain("loudness_tolerance_lu requires target_lufs"); expect(validateDeliveryConformanceContract({ videoCodec: "h264", frameRateTolerance: 0.01 })).toContain("frame_rate_tolerance requires frame_rate"); expect(validateDeliveryConformanceContract({ videoCodec: " " })).toContain("non-empty"); expect(validateDeliveryConformanceContract({ audioCodec: "" })).toContain("non-empty"); }); it("falls back from unusable frame-rate metadata and does not fail missing measurements", () => { const checks = evaluateDeliveryConformance({ format: { bit_rate: "12000000" }, streams: [{ codec_type: "video", avg_frame_rate: "0/1", r_frame_rate: "24/1", bit_rate: "N/A" }], }, { frameRate: 24, minimumVideoBitrateKbps: 11000, targetLufs: -23, maximumTruePeakDbfs: -1, }, { integratedLufs: -23, truePeakDbfs: null }); expect(checks.find(check => check.id === "frame_rate")?.status).toBe("pass"); expect(checks.find(check => check.id === "minimum_video_bitrate")).toMatchObject({ status: "not_evaluated", detail: "Video bitrate metadata was unavailable", }); expect(checks.find(check => check.id === "integrated_loudness")?.status).toBe("pass"); expect(checks.find(check => check.id === "true_peak")?.status).toBe("not_evaluated"); }); it("reports matching and mismatching fields independently", () => { const checks = evaluateDeliveryConformance(probe, { allowedContainerNames: ["mp4"], videoCodec: "h264", audioCodec: "pcm_s24le", width: 1920, height: 720, frameRate: 29.97, frameRateTolerance: 0.01, durationSeconds: 10, durationToleranceSeconds: 0.05, minimumVideoBitrateKbps: 9000, maximumVideoBitrateKbps: 11000, audioSampleRateHz: 48000, audioChannels: 2, }); expect(checks.find(check => check.id === "container_demuxer_family")).toMatchObject({ status: "pass", detail: expect.stringContaining("do not identify an exact container subtype"), }); expect(checks.find(check => check.id === "audio_codec")?.status).toBe("fail"); expect(checks.find(check => check.id === "height")?.status).toBe("fail"); expect(checks.find(check => check.id === "frame_rate")?.status).toBe("pass"); expect(checks.find(check => check.id === "maximum_video_bitrate")?.status).toBe("pass"); }); it("fails expected streams that are missing and preserves unavailable loudness", () => { const checks = evaluateDeliveryConformance({ format: {}, streams: [] }, { videoCodec: "prores", audioChannels: 2, targetLufs: -23, maximumTruePeakDbfs: -1, }, null, "No audio stream was available for EBU R128 analysis"); expect(checks.find(check => check.id === "video_codec")?.status).toBe("fail"); expect(checks.find(check => check.id === "audio_channels")?.status).toBe("fail"); expect(checks.find(check => check.id === "integrated_loudness")?.status).toBe("not_evaluated"); expect(checks.find(check => check.id === "true_peak")?.status).toBe("not_evaluated"); }); it("evaluates loudness failures and does not evaluate video bitrate without video", () => { const checks = evaluateDeliveryConformance({ format: { format_name: "matroska", bit_rate: "5000000" }, streams: [{ codec_type: "audio", codec_name: "aac" }] }, { allowedContainerNames: ["mov"], minimumVideoBitrateKbps: 1000, maximumVideoBitrateKbps: 2000, targetLufs: -23, loudnessToleranceLu: 0.5, maximumTruePeakDbfs: -1, }, { integratedLufs: -20, truePeakDbfs: -0.5 }); expect(checks.find(check => check.id === "minimum_video_bitrate")).toMatchObject({ status: "not_evaluated", detail: expect.stringContaining("No video stream"), }); expect(checks.find(check => check.id === "maximum_video_bitrate")?.status).toBe("not_evaluated"); expect(checks.filter(check => !check.id.includes("video_bitrate")).every(check => check.status === "fail")).toBe(true); const missingBitrate = evaluateDeliveryConformance({ format: {}, streams: [{ codec_type: "video", bit_rate: "N/A" }] }, { minimumVideoBitrateKbps: 1000, }); expect(missingBitrate.find(check => check.id === "minimum_video_bitrate")).toMatchObject({ status: "not_evaluated", detail: "Video bitrate metadata was unavailable", }); const coverArtOnly = evaluateDeliveryConformance({ format: { bit_rate: "5000000" }, streams: [{ codec_type: "video", codec_name: "mjpeg", width: 1000, disposition: { attached_pic: 1 } }], }, { videoCodec: "mjpeg", width: 1000, minimumVideoBitrateKbps: 1000 }); expect(coverArtOnly.find(check => check.id === "video_codec")?.status).toBe("fail"); expect(coverArtOnly.find(check => check.id === "width")?.status).toBe("fail"); expect(coverArtOnly.find(check => check.id === "minimum_video_bitrate")?.status).toBe("not_evaluated"); }); it("does not treat unavailable numeric metadata as a mismatch", () => { const checks = evaluateDeliveryConformance({ format: { duration: "N/A", bit_rate: "5000000" }, streams: [{ codec_type: "video", width: "N/A", height: "N/A", avg_frame_rate: "0/0", r_frame_rate: "0/0" }], }, { width: 1920, height: 1080, frameRate: 24, durationSeconds: 10, minimumVideoBitrateKbps: 1000, }); for (const id of ["width", "height", "frame_rate", "duration", "minimum_video_bitrate"]) { expect(checks.find(check => check.id === id)?.status).toBe("not_evaluated"); } }); it("does not evaluate video bitrate from aggregate format bitrate", () => { const checks = evaluateDeliveryConformance({ format: { bit_rate: "5000000" }, streams: [{ codec_type: "video", bit_rate: "1000000" }], }, { minimumVideoBitrateKbps: 3000, maximumVideoBitrateKbps: 3000 }); expect(checks.find(check => check.id === "minimum_video_bitrate")?.status).toBe("fail"); expect(checks.find(check => check.id === "maximum_video_bitrate")?.status).toBe("pass"); }); }); describe("verify_delivery_conformance boundary", () => { const tool = getExportTools({ tempDir: "/tmp/test" }).verify_delivery_conformance; beforeEach(() => vi.clearAllMocks()); it("reports its local filesystem-only operational boundary", () => { expect(tool.operationalCapability).toMatchObject({ backend: "local", backends: ["local"], authority: "filesystem", verificationBoundary: "local_filesystem", hostVerificationRequired: false, minimumPremiereVersion: null, }); }); function mediaFile() { const directory = mkdtempSync(join(tmpdir(), "premiere-delivery-conformance-")); const mediaPath = join(directory, "delivery.mp4"); writeFileSync(mediaPath, "delivery-fixture"); return mediaPath; } it("returns an explicit failure for a missing baseline file", async () => { const missingPath = join(tmpdir(), `missing-delivery-${Date.now()}.mp4`); await expect(tool.handler({ output_path: missingPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("not found on disk") }); expect(mockedExecFileAsync).not.toHaveBeenCalled(); }); it("returns a complete local conformance report", async () => { const mediaPath = mediaFile(); mockedExecFileAsync .mockResolvedValueOnce({ stdout: JSON.stringify(probe), stderr: "" }) .mockResolvedValueOnce({ stdout: "", stderr: "Summary:\n Integrated loudness:\n I: -23.0 LUFS\n True peak:\n Peak: -2.0 dBFS" }); await expect(tool.handler({ output_path: mediaPath, allowed_container_names: ["mp4"], video_codec: "h264", frame_rate: 29.97, frame_rate_tolerance: 0.01, target_lufs: -23, maximum_true_peak_dbfs: -1, })).resolves.toMatchObject({ success: true, data: { mediaPath, conforms: true, evaluated: 5, notEvaluated: 0 }, }); expect(mockedExecFileAsync).toHaveBeenCalledTimes(2); expect(mockedExecFileAsync).toHaveBeenNthCalledWith(1, "ffprobe", expect.arrayContaining(["-protocol_whitelist", "file,crypto,data"]), expect.any(Object)); expect(mockedExecFileAsync).toHaveBeenNthCalledWith(2, "ffmpeg", expect.arrayContaining(["-protocol_whitelist", "file,crypto,data", "-map", "0:a:0"]), expect.any(Object)); }); it("keeps ffprobe process failures explicit", async () => { const mediaPath = mediaFile(); mockedExecFileAsync.mockRejectedValueOnce(Object.assign(new Error("probe failed"), { stderr: "invalid media" })); await expect(tool.handler({ output_path: mediaPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("invalid media") }); const emptyStderrPath = mediaFile(); mockedExecFileAsync.mockRejectedValueOnce(Object.assign(new Error("probe failed"), { stderr: "" })); await expect(tool.handler({ output_path: emptyStderrPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("probe failed") }); const noisyStderrPath = mediaFile(); mockedExecFileAsync.mockRejectedValueOnce(Object.assign(new Error("probe failed"), { stderr: "x".repeat(5_000_000) })); const result = await tool.handler({ output_path: noisyStderrPath, video_codec: "h264" }); expect(result).toMatchObject({ success: false, error: expect.stringContaining("ffprobe delivery conformance inspection failed:") }); expect(result.error).toHaveLength(4_096 + "ffprobe delivery conformance inspection failed: ".length); expect(result.error.endsWith("…")).toBe(true); }); it("reports ffprobe timeouts and refuses a file that changes during inspection", async () => { const timedOutPath = mediaFile(); mockedExecFileAsync.mockRejectedValueOnce(Object.assign(new Error("timeout"), { killed: true })); await expect(tool.handler({ output_path: timedOutPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("timed out") }); const changingPath = mediaFile(); mockedExecFileAsync.mockImplementationOnce(async () => { appendFileSync(changingPath, "changed"); return { stdout: JSON.stringify(probe), stderr: "" }; }); await expect(tool.handler({ output_path: changingPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("changed during") }); const disappearingPath = mediaFile(); mockedExecFileAsync.mockImplementationOnce(async () => { unlinkSync(disappearingPath); return { stdout: JSON.stringify(probe), stderr: "" }; }); await expect(tool.handler({ output_path: disappearingPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("changed during") }); const rejectedAfterDeletionPath = mediaFile(); mockedExecFileAsync.mockImplementationOnce(async () => { unlinkSync(rejectedAfterDeletionPath); throw Object.assign(new Error("probe failed"), { stderr: "invalid media" }); }); await expect(tool.handler({ output_path: rejectedAfterDeletionPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("changed during") }); const invalidAfterChangePath = mediaFile(); mockedExecFileAsync.mockImplementationOnce(async () => { appendFileSync(invalidAfterChangePath, "changed"); return { stdout: "null", stderr: "" }; }); await expect(tool.handler({ output_path: invalidAfterChangePath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("changed during") }); }); it("handles missing tools, invalid probe JSON, and unavailable loudness without overclaiming", async () => { const missingToolPath = mediaFile(); mockedExecFileAsync.mockRejectedValueOnce(Object.assign(new Error("missing"), { code: "ENOENT" })); await expect(tool.handler({ output_path: missingToolPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("ffprobe was not found") }); const invalidJsonPath = mediaFile(); mockedExecFileAsync.mockResolvedValueOnce({ stdout: "null", stderr: "" }); await expect(tool.handler({ output_path: invalidJsonPath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("invalid delivery report") }); const incompleteProbePath = mediaFile(); mockedExecFileAsync.mockResolvedValueOnce({ stdout: JSON.stringify({ format: {} }), stderr: "" }); await expect(tool.handler({ output_path: incompleteProbePath, video_codec: "h264" })) .resolves.toMatchObject({ success: false, error: expect.stringContaining("invalid delivery report") }); const silentPath = mediaFile(); mockedExecFileAsync.mockResolvedValueOnce({ stdout: JSON.stringify({ format: {}, streams: [] }), stderr: "" }); await expect(tool.handler({ output_path: silentPath, target_lufs: -23 })) .resolves.toMatchObject({ success: true, data: { conforms: false, evaluated: 0, notEvaluated: 1 } }); const unreadableAudioPath = mediaFile(); mockedExecFileAsync .mockResolvedValueOnce({ stdout: JSON.stringify(probe), stderr: "" }) .mockRejectedValueOnce(Object.assign(new Error("decode"), { stderr: "no measurement" })); await expect(tool.handler({ output_path: unreadableAudioPath, target_lufs: -23 })) .resolves.toMatchObject({ success: true, data: { conforms: false, notEvaluated: 1 } }); const partialAudioPath = mediaFile(); mockedExecFileAsync .mockResolvedValueOnce({ stdout: JSON.stringify(probe), stderr: "" }) .mockRejectedValueOnce(Object.assign(new Error("decode"), { stderr: "Summary:\n Integrated loudness:\n I: -23.0 LUFS\n True peak:\n Peak: -2.0 dBFS" })); await expect(tool.handler({ output_path: partialAudioPath, target_lufs: -23, maximum_true_peak_dbfs: -1 })) .resolves.toMatchObject({ success: true, data: { conforms: false, evaluated: 0, notEvaluated: 2 } }); }); });