134 lines · 4.4 KB · TypeScript
RawDownload
import { expect, test } from "bun:test";import { mkdtempSync, readdirSync, rmSync, statSync } from "node:fs";import { writeFile } from "node:fs/promises";import { tmpdir } from "node:os";import { join } from "node:path";import {  MAX_VOICE_UPLOAD_BYTES,  normalizeVoiceReference,  VoiceReferenceError,} from "./reference-audio"; const wave = (durationMs: number): Buffer => {  const dataBytes = Math.round(48_000 * (durationMs / 1000));  const bytes = Buffer.alloc(44 + dataBytes);  bytes.write("RIFF", 0);  bytes.writeUInt32LE(bytes.length - 8, 4);  bytes.write("WAVE", 8);  bytes.write("fmt ", 12);  bytes.writeUInt32LE(16, 16);  bytes.writeUInt16LE(1, 20);  bytes.writeUInt16LE(1, 22);  bytes.writeUInt32LE(24_000, 24);  bytes.writeUInt32LE(48_000, 28);  bytes.writeUInt16LE(2, 32);  bytes.writeUInt16LE(16, 34);  bytes.write("data", 36);  bytes.writeUInt32LE(dataBytes, 40);  return bytes;}; const fixture = (): string => mkdtempSync(join(tmpdir(), "local-studio-reference-"));const input = (): Buffer => {  const bytes = Buffer.alloc(12);  bytes.write("RIFF", 0);  bytes.write("WAVE", 8);  return bytes;}; test("normalizes a bounded reference and removes temporary plaintext", async () => {  const directory = fixture();  try {    let receivedFormat = "";    let plaintextMode = 0;    const result = await normalizeVoiceReference(input(), directory, {      ffmpegPath: () => "/fake/ffmpeg",      transcode: async (_command, _input, format, output) => {        receivedFormat = format;        await writeFile(output, wave(10_000), { mode: 0o666 });        plaintextMode = statSync(output).mode & 0o777;      },    });     expect(result.durationMs).toBe(10_000);    expect(result.audio).toEqual(wave(10_000));    expect(receivedFormat).toBe("wav");    expect(plaintextMode).toBe(0o600);    expect(readdirSync(join(directory, "runtime", "speech", "uploads"))).toEqual([]);    expect(statSync(join(directory, "runtime", "speech", "uploads")).mode & 0o777).toBe(0o700);  } finally {    rmSync(directory, { recursive: true, force: true });  }}); test("rejects unavailable decoding, oversized input, and invalid duration", async () => {  const directory = fixture();  try {    await expect(      normalizeVoiceReference(input(), directory, {        ffmpegPath: () => null,        transcode: async () => undefined,      }),    ).rejects.toMatchObject({ code: "ffmpeg_missing" });    await expect(      normalizeVoiceReference(Buffer.alloc(MAX_VOICE_UPLOAD_BYTES + 1), directory),    ).rejects.toBeInstanceOf(VoiceReferenceError);    await expect(      normalizeVoiceReference(input(), directory, {        ffmpegPath: () => "/fake/ffmpeg",        transcode: async (_command, _input, _format, output) => {          await writeFile(output, wave(5_999));        },      }),    ).rejects.toMatchObject({ code: "voice_duration_invalid" });  } finally {    rmSync(directory, { recursive: true, force: true });  }}); test("rejects malformed normalized output and still removes it", async () => {  const directory = fixture();  try {    await expect(      normalizeVoiceReference(input(), directory, {        ffmpegPath: () => "/fake/ffmpeg",        transcode: async (_command, _input, _format, output) => {          await writeFile(output, Buffer.from("not-wave"));        },      }),    ).rejects.toMatchObject({ code: "voice_audio_invalid" });    expect(readdirSync(join(directory, "runtime", "speech", "uploads"))).toEqual([]);  } finally {    rmSync(directory, { recursive: true, force: true });  }}); test("rejects playlists and indirection before invoking FFmpeg", async () => {  const directory = fixture();  let invoked = false;  try {    await expect(      normalizeVoiceReference(Buffer.from("#EXTM3U\nhttps://example.com/voice.wav\n"), directory, {        ffmpegPath: () => "/fake/ffmpeg",        transcode: async () => {          invoked = true;        },      }),    ).rejects.toMatchObject({ code: "voice_audio_invalid" });    await expect(      normalizeVoiceReference(        Buffer.from("ffconcat version 1.0\nfile '/etc/passwd'\n"),        directory,        {          ffmpegPath: () => "/fake/ffmpeg",          transcode: async () => {            invoked = true;          },        },      ),    ).rejects.toMatchObject({ code: "voice_audio_invalid" });    expect(invoked).toBe(false);  } finally {    rmSync(directory, { recursive: true, force: true });  }});