Files
cycle-atlas/.claude/skills/media-use/audio/scripts/lib/sfx.test.mjs
T

331 lines
12 KiB
JavaScript
Raw Normal View History

import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, writeFileSync, existsSync, readFileSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { appendRecord } from "../../../scripts/lib/manifest.mjs";
import { BUNDLED_SFX_DIR, findSoundEffect, resolveSfx } from "./sfx.mjs";
// No real network: each test serves Openverse's answers; by default it is unreachable.
const offline = async () => {
throw new TypeError("fetch failed");
};
let serve = offline;
const UNREACHABLE =
"Openverse unreachable (fetch failed): the remaining SFX cues use the bundled library";
globalThis.fetch = (url, init) => serve(String(url), init);
// Offline SFX resolution: the bundled library may ship manifest.json
// without the actual mp3s. The old code copied only when the source existed but
// pushed the sfx entry unconditionally — producing a dangling reference that
// silently dropped downstream ("not on disk"). These tests lock in the loud
// behavior: a present file is copied + referenced; a missing file yields an
// anomaly and NO dangling entry.
async function withDirs(fn) {
const root = mkdtempSync(join(tmpdir(), "hf-sfx-"));
const libDir = join(root, "lib");
const projDir = join(root, "proj");
mkdirSync(libDir, { recursive: true });
mkdirSync(projDir, { recursive: true });
try {
// `await` is load-bearing: without it the finally cleanup runs before the
// async test body resolves, deleting the temp dir mid-assertion.
return await fn({ libDir, projDir });
} finally {
rmSync(root, { recursive: true, force: true });
}
}
test("offline: copies and references a present bundled file", async () => {
await withDirs(async ({ libDir, projDir }) => {
writeFileSync(
join(libDir, "manifest.json"),
JSON.stringify({ whoosh: { file: "whoosh.mp3", duration: 0.8 } }),
);
writeFileSync(join(libDir, "whoosh.mp3"), "ID3-fake-bytes");
const { sfx, anomalies } = await resolveSfx({
cues: [{ id: "s1", name: "whoosh" }],
hyperframesDir: projDir,
sfxLibDir: libDir,
});
assert.equal(sfx.length, 1);
assert.equal(sfx[0].file, "assets/sfx/whoosh.mp3");
assert.equal(sfx[0].source, "local");
assert.ok(existsSync(join(projDir, "assets/sfx/whoosh.mp3")), "mp3 copied into project");
assert.deepEqual(anomalies, [UNREACHABLE]);
});
});
test("offline: a matched-but-missing bundled file yields an anomaly and NO dangling entry", async () => {
await withDirs(async ({ libDir, projDir }) => {
// Manifest names whoosh.mp3, but the mp3 was never shipped (the reported bug).
writeFileSync(
join(libDir, "manifest.json"),
JSON.stringify({ whoosh: { file: "whoosh.mp3", duration: 0.8 } }),
);
const { sfx, anomalies } = await resolveSfx({
cues: [{ id: "s1", name: "whoosh" }],
hyperframesDir: projDir,
sfxLibDir: libDir,
});
assert.equal(sfx.length, 0, "no dangling entry for a file that was never copied");
assert.equal(anomalies.length, 2);
assert.match(anomalies[1], /missing from the offline library/);
assert.ok(!existsSync(join(projDir, "assets/sfx/whoosh.mp3")), "nothing copied");
});
});
const whooshLibrary = (libDir, withFile) => {
writeFileSync(
join(libDir, "manifest.json"),
JSON.stringify({ whoosh: { file: "whoosh.mp3", duration: 0.8 } }),
);
if (withFile) writeFileSync(join(libDir, "whoosh.mp3"), "ID3-library-bytes");
};
const record = (projDir, source) =>
appendRecord(projDir, { id: "sfx_001", type: "sfx", path: "assets/sfx/whoosh.mp3", source });
const bundledOnly = (libDir, projDir) =>
resolveSfx({
cues: [{ id: "s1", name: "whoosh" }],
hyperframesDir: projDir,
sfxLibDir: libDir,
});
test("offline: the engine's earlier copy stands in for a library file this install lacks", async () => {
await withDirs(async ({ libDir, projDir }) => {
whooshLibrary(libDir, false);
mkdirSync(join(projDir, "assets/sfx"), { recursive: true });
writeFileSync(join(projDir, "assets/sfx/whoosh.mp3"), "engine copy");
record(projDir, "bundled");
const { sfx, anomalies } = await bundledOnly(libDir, projDir);
assert.deepEqual(
sfx.map(({ file }) => file),
["assets/sfx/whoosh.mp3"],
);
assert.deepEqual(anomalies, [UNREACHABLE]);
});
});
test("offline: a person's file with the library's bytes stays theirs once recorded as their own", async () => {
await withDirs(async ({ libDir, projDir }) => {
whooshLibrary(libDir, true);
mkdirSync(join(projDir, "assets/sfx"), { recursive: true });
writeFileSync(join(projDir, "assets/sfx/whoosh.mp3"), "ID3-library-bytes");
record(projDir, "existing");
const { sfx } = await bundledOnly(libDir, projDir);
assert.deepEqual(
sfx.map(({ file }) => file),
["assets/sfx/whoosh-2.mp3"],
);
assert.equal(readFileSync(join(projDir, "assets/sfx/whoosh.mp3"), "utf8"), "ID3-library-bytes");
});
});
const libraryWith = (libDir, names) => {
const manifest = {};
for (const name of names) {
manifest[name] = { file: `${name}.mp3`, duration: 0.5 };
writeFileSync(join(libDir, `${name}.mp3`), `library ${name}`);
}
writeFileSync(join(libDir, "manifest.json"), JSON.stringify(manifest));
};
const sound = (overrides = {}) => ({
id: "ov-1",
title: "Swoosh",
creator: "Ana",
license: "by",
foreign_landing_url: "https://freesound.org/s/1",
url: "https://cdn.freesound.test/swoosh.mp3",
filetype: "mp3",
duration: 820,
attribution: '"Swoosh" by Ana is licensed under CC BY 4.0.',
...overrides,
});
// Openverse stand-in: `answer(query)` gives a search response; any other URL is the sound file.
function openverse(answer) {
const searches = [];
serve = async (url) => {
const query = new URL(url).searchParams.get("q");
if (!url.startsWith("https://api.openverse.org/")) return new Response(`bytes of ${url}`);
searches.push(query);
return answer(query);
};
return searches;
}
const run = (libDir, projDir, names) =>
resolveSfx({
cues: names.map((name, index) => ({ id: String(index + 1), name })),
hyperframesDir: projDir,
sfxLibDir: libDir,
});
test("openverse: each cue gets the best licensed sound, with its licence and credit", async () => {
await withDirs(async ({ libDir, projDir }) => {
libraryWith(libDir, ["whoosh"]);
openverse(() => Response.json({ results: [sound()] }));
try {
const { sfx, anomalies } = await run(libDir, projDir, ["whoosh"]);
assert.deepEqual(sfx, [
{
id: "1",
name: "whoosh",
file: "assets/sfx/whoosh.mp3",
source: "openverse",
duration_s: 0.82,
license: "by",
credit: '"Swoosh" by Ana is licensed under CC BY 4.0.',
offset_s: 0,
volume: 0.35,
},
]);
assert.deepEqual(anomalies, []);
assert.equal(
readFileSync(join(projDir, "assets/sfx/whoosh.mp3"), "utf8"),
"bytes of https://cdn.freesound.test/swoosh.mp3",
);
assert.match(
readFileSync(join(projDir, "assets/sfx/CREDITS.md"), "utf8"),
/- `assets\/sfx\/whoosh\.mp3`: "Swoosh" by Ana is licensed under CC BY 4\.0\. Source: https:\/\/freesound\.org\/s\/1/,
);
} finally {
serve = offline;
}
});
});
test("openverse: a rate limit sends this and every later cue to the bundled library, asking once", async () => {
await withDirs(async ({ libDir, projDir }) => {
libraryWith(libDir, ["whoosh", "pop"]);
const searches = openverse(() => new Response("slow down", { status: 429 }));
try {
const { sfx, anomalies } = await run(libDir, projDir, ["whoosh", "pop"]);
assert.deepEqual(searches, ["whoosh"]);
assert.deepEqual(
sfx.map(({ file, source }) => [file, source]),
[
["assets/sfx/whoosh.mp3", "local"],
["assets/sfx/pop.mp3", "local"],
],
);
assert.equal(readFileSync(join(projDir, "assets/sfx/pop.mp3"), "utf8"), "library pop");
assert.deepEqual(anomalies, [
"Openverse rate limit reached (HTTP 429): the remaining SFX cues use the bundled library",
]);
} finally {
serve = offline;
}
});
});
test("openverse: a cue with no licensed match falls back to the bundled library alone", async () => {
await withDirs(async ({ libDir, projDir }) => {
libraryWith(libDir, ["pop"]);
const searches = openverse((query) =>
Response.json({ results: query === "pop" ? [sound({ license: "by-nc" })] : [sound()] }),
);
try {
const { sfx } = await run(libDir, projDir, ["pop", "swoosh"]);
assert.deepEqual(searches, ["pop", "swoosh"]);
assert.deepEqual(
sfx.map(({ file, source }) => [file, source]),
[
["assets/sfx/pop.mp3", "local"],
["assets/sfx/swoosh.mp3", "openverse"],
],
);
} finally {
serve = offline;
}
});
});
test("openverse: a failed download falls back to the bundled file with an anomaly", async () => {
await withDirs(async ({ libDir, projDir }) => {
libraryWith(libDir, ["whoosh"]);
serve = async (url) =>
url.startsWith("https://api.openverse.org/")
? Response.json({ results: [sound()] })
: new Response("gone", { status: 404 });
try {
const { sfx, anomalies } = await run(libDir, projDir, ["whoosh"]);
assert.deepEqual(
sfx.map(({ file, source }) => [file, source]),
[["assets/sfx/whoosh.mp3", "local"]],
);
assert.match(anomalies[0], /Openverse download failed — download HTTP 404/);
} finally {
serve = offline;
}
});
});
test("openverse: one effect named in two lines is searched and downloaded once", async () => {
await withDirs(async ({ libDir, projDir }) => {
libraryWith(libDir, []);
const searches = openverse(() => Response.json({ results: [sound({ license: "cc0" })] }));
try {
const { sfx } = await run(libDir, projDir, ["whoosh", "whoosh"]);
assert.deepEqual(searches, ["whoosh"]);
assert.deepEqual(
sfx.map(({ id, file }) => [id, file]),
[
["1", "assets/sfx/whoosh.mp3"],
["2", "assets/sfx/whoosh.mp3"],
],
);
assert.equal(
existsSync(join(projDir, "assets/sfx/CREDITS.md")),
false,
"CC0 needs no credit",
);
} finally {
serve = offline;
}
});
});
test("findSoundEffect: a host gets the saved file, licence, credit and duration for one query", async () => {
await withDirs(async ({ projDir }) => {
const searches = openverse(() => Response.json({ results: [sound()] }));
try {
assert.deepEqual(await findSoundEffect("whoosh", { hyperframesDir: projDir }), {
sound: {
file: "assets/sfx/whoosh.mp3",
source: "openverse",
duration_s: 0.82,
license: "by",
credit: '"Swoosh" by Ana is licensed under CC BY 4.0.',
},
anomalies: [],
});
assert.deepEqual(searches, ["whoosh"]);
} finally {
serve = offline;
}
});
});
test("findSoundEffect: offline, the skill's own bundled library answers", async () => {
await withDirs(async ({ projDir }) => {
const { sound, anomalies } = await findSoundEffect("whoosh", { hyperframesDir: projDir });
assert.deepEqual(sound, {
file: "assets/sfx/whoosh.mp3",
source: "local",
duration_s: sound.duration_s,
});
assert.deepEqual(
readFileSync(join(projDir, sound.file)),
readFileSync(join(BUNDLED_SFX_DIR, "whoosh.mp3")),
);
assert.deepEqual(anomalies, [UNREACHABLE]);
assert.equal(
(await findSoundEffect("no such sound at all", { hyperframesDir: projDir })).sound,
null,
);
});
});