fix: PlayRelease always materialises a defensive copy so Items alias can't wipe the queue on jump; add aliasing regression test
This commit is contained in:
@@ -56,7 +56,7 @@ public sealed class QueueService : IQueueService, IDisposable
|
|||||||
|
|
||||||
public async Task PlayRelease(IEnumerable<TrackDto> tracks, int startIndex = 0)
|
public async Task PlayRelease(IEnumerable<TrackDto> tracks, int startIndex = 0)
|
||||||
{
|
{
|
||||||
var list = tracks as IReadOnlyList<TrackDto> ?? tracks.ToList();
|
var list = tracks.ToList();
|
||||||
if (list.Count == 0) return;
|
if (list.Count == 0) return;
|
||||||
|
|
||||||
var start = Math.Clamp(startIndex, 0, list.Count - 1);
|
var start = Math.Clamp(startIndex, 0, list.Count - 1);
|
||||||
|
|||||||
@@ -144,6 +144,33 @@ public class QueueServiceTests
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task PlayRelease_ViaLiveQueueItems_PreservesTracksAndJumpsToIndex()
|
||||||
|
{
|
||||||
|
// Regression guard for the aliasing bug: OnQueueJump calls PlayRelease(QueueService.Items, index).
|
||||||
|
// Items returns the backing list directly; without a defensive copy, the cast
|
||||||
|
// "tracks as IReadOnlyList<TrackDto>" aliases _items, so _items.Clear() also clears list,
|
||||||
|
// and _items.AddRange(list) adds nothing — wiping the queue and playing nothing.
|
||||||
|
await _queue.PlayRelease(Tracks(4)); // populate the live queue
|
||||||
|
|
||||||
|
// Jump to index 2 via the live Items reference, exactly as OnQueueJump does.
|
||||||
|
await _queue.PlayRelease(_queue.Items, 2);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
// The queue must survive — all four tracks still present, in order.
|
||||||
|
Assert.That(_queue.Items, Has.Count.EqualTo(4));
|
||||||
|
Assert.That(_queue.Items.Select(t => t.EntryKey),
|
||||||
|
Is.EqualTo(new[] { "track-1", "track-2", "track-3", "track-4" }));
|
||||||
|
// CurrentIndex must be the jumped-to slot.
|
||||||
|
Assert.That(_queue.CurrentIndex, Is.EqualTo(2));
|
||||||
|
// Current must be the right track.
|
||||||
|
Assert.That(_queue.Current!.EntryKey, Is.EqualTo("track-3"));
|
||||||
|
// The player must have streamed the jumped-to track.
|
||||||
|
Assert.That(_player.SelectedTracks.Last().EntryKey, Is.EqualTo("track-3"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// --- Arm: prerender-safe load without streaming (release embed) ---
|
// --- Arm: prerender-safe load without streaming (release embed) ---
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
Reference in New Issue
Block a user