apprt/gtk: add regression test for audio-bell MediaFile reuse

Guards the contract that prevents the bell thread leak: bellMediaFile
must return the same cached MediaFile for an unchanged path and only
rebuild when the path changes. A revert to per-bell allocation (the
leak) would fail this. Runs in the existing test-gtk CI job; needs no
display or playback since the path bookkeeping is all that's asserted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Nikolay Bryskin
2026-05-25 23:10:34 +03:00
parent 0b6d91e531
commit 0708f932a5

View File

@@ -127,3 +127,31 @@ fn mediaFileError(
err.f_message orelse "",
});
}
test "bellMediaFile reuses one MediaFile per path" {
// Regression guard for the audio-bell thread leak: each bell must replay a
// single cached MediaFile, not allocate a fresh GStreamer pipeline (which
// leaked gstglcontext/gldisplay-event threads) per ring. We assert the
// reuse contract of bellMediaFile directly; this needs no display and no
// playback (MediaFile is lazy), only that the path comparison drives reuse.
const testing = std.testing;
// The files need not exist: MediaFile only records the path until played.
const path_a: [:0]const u8 = "/tmp/ghostty-bell-test-a.oga";
const path_b: [:0]const u8 = "/tmp/ghostty-bell-test-b.oga";
var current = bellMediaFile(null, path_a, false) orelse return error.SkipZigTest;
const first = current;
try testing.expect(isForPath(current, path_a));
// Same path => identical object (the leak regression is rebuilding here).
current = bellMediaFile(current, path_a, false).?;
try testing.expectEqual(first, current);
// Changed path => rebuilt object targeting the new path (old one freed).
current = bellMediaFile(current, path_b, false) orelse return error.SkipZigTest;
try testing.expect(isForPath(current, path_b));
try testing.expect(!isForPath(current, path_a));
current.unref();
}