fix(r5): address the fifth /code-review high round — 6 findings
- run_ffmpeg stops the process from ONE exit path (`except BaseException`), so an exception out of on_progress (a DB write) can no longer orphan a live ffmpeg after a 10s join on its pipes; _stop is now a no-op on a dead process - both run_ffmpeg callbacks are throttled to ~1s (they were a DB round-trip per output line: ~10^5 queries on a long re-encode), mirroring the download hook - volume arithmetic extracted to lib/playerVolume with unit tests; a corrupt level now falls back to the LAST GOOD one instead of full blast, and the sanitising happens where the stored value enters - RSS is back to two except clauses (the shared tail already sits after the try) - new tests: callback-exception cleanup, the two throttles; the fake Popen grew poll() and its wait count is now asserted Mutation-checked: each new group goes red when its fix is reverted.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { DEFAULT_VOLUME, normalizeVolume, stepVolume } from "./playerVolume";
|
||||
|
||||
describe("normalizeVolume", () => {
|
||||
it("keeps a valid level", () => {
|
||||
expect(normalizeVolume(0)).toBe(0);
|
||||
expect(normalizeVolume(37)).toBe(37);
|
||||
expect(normalizeVolume(100)).toBe(100);
|
||||
});
|
||||
|
||||
it("clamps out-of-range levels and rounds to whole percents", () => {
|
||||
expect(normalizeVolume(-20)).toBe(0);
|
||||
expect(normalizeVolume(150)).toBe(100);
|
||||
expect(normalizeVolume(42.6)).toBe(43);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["a missing key", undefined],
|
||||
["an explicit null", null],
|
||||
["a stringified number", "80"],
|
||||
["NaN from a broken player", NaN],
|
||||
["a whole object", { volume: 50 }],
|
||||
])("falls back on %s", (_label, raw) => {
|
||||
// The regression: a partial stored object made the level undefined, which Math.round turned
|
||||
// into NaN — muting playback and persisting `null` for every later session.
|
||||
expect(normalizeVolume(raw, 15)).toBe(15);
|
||||
});
|
||||
|
||||
it("prefers the last known level over the default, so a quiet session stays quiet", () => {
|
||||
expect(normalizeVolume(NaN, 15)).toBe(15);
|
||||
expect(normalizeVolume(NaN, 15)).not.toBe(DEFAULT_VOLUME);
|
||||
});
|
||||
|
||||
it("uses the default when the fallback is unusable too", () => {
|
||||
expect(normalizeVolume(NaN, NaN)).toBe(DEFAULT_VOLUME);
|
||||
expect(normalizeVolume(null, undefined as unknown as number)).toBe(DEFAULT_VOLUME);
|
||||
});
|
||||
});
|
||||
|
||||
describe("stepVolume", () => {
|
||||
it("steps up and down from the current level", () => {
|
||||
expect(stepVolume(60, 5, 100)).toBe(65);
|
||||
expect(stepVolume(60, -5, 100)).toBe(55);
|
||||
});
|
||||
|
||||
it("clamps at both ends instead of wrapping", () => {
|
||||
expect(stepVolume(98, 5, 100)).toBe(100);
|
||||
expect(stepVolume(3, -5, 100)).toBe(0);
|
||||
});
|
||||
|
||||
it("steps from the fallback when the player answers garbage", () => {
|
||||
// A spin must not lose notches to a stale/unusable reading — it continues from what we last set.
|
||||
expect(stepVolume(undefined, -5, 90)).toBe(85);
|
||||
expect(stepVolume(NaN, -5, 90)).toBe(85);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user