Merge p17-w2-t1-docked-overlay into dev (Phase 17 Wave 17.2: docked queue overlay + ClearUpcoming)
This commit is contained in:
@@ -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) ---
|
||||
|
||||
[Test]
|
||||
@@ -678,6 +705,75 @@ public class QueueServiceTests
|
||||
});
|
||||
}
|
||||
|
||||
// --- ClearUpcoming (OQ5: keep the current track, drop the up-next) — Phase 17 wave 17.2 ---
|
||||
|
||||
[Test]
|
||||
public async Task ClearUpcoming_KeepsCurrentTrack_DropsTheRest_WithoutStopping()
|
||||
{
|
||||
// Current = track-2; ClearUpcoming leaves only track-2 at index 0 and does not stop the player.
|
||||
await _queue.PlayRelease(Tracks(4), startIndex: 1);
|
||||
var streamedBefore = _player.SelectedTracks.Count;
|
||||
|
||||
_queue.ClearUpcoming();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_queue.Items.Select(t => t.EntryKey), Is.EqualTo(new[] { "track-2" }));
|
||||
Assert.That(_queue.CurrentIndex, Is.EqualTo(0));
|
||||
Assert.That(_queue.Current!.EntryKey, Is.EqualTo("track-2"));
|
||||
Assert.That(_queue.HasNext, Is.False);
|
||||
Assert.That(_queue.HasPrevious, Is.False);
|
||||
Assert.That(_player.StopCount, Is.EqualTo(0), "ClearUpcoming must not stop playback (C2)");
|
||||
Assert.That(_player.SelectedTracks, Has.Count.EqualTo(streamedBefore),
|
||||
"ClearUpcoming must not re-stream");
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ClearUpcoming_RaisesQueueChangedOnce()
|
||||
{
|
||||
await _queue.PlayRelease(Tracks(3));
|
||||
var changed = 0;
|
||||
_queue.QueueChanged += () => changed++;
|
||||
|
||||
_queue.ClearUpcoming();
|
||||
|
||||
Assert.That(changed, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ClearUpcoming_WhenOnlyCurrentRemains_IsNoOpAndDoesNotRaiseQueueChanged()
|
||||
{
|
||||
await _queue.PlayRelease(Tracks(1));
|
||||
var raised = false;
|
||||
_queue.QueueChanged += () => raised = true;
|
||||
|
||||
_queue.ClearUpcoming();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_queue.Items, Has.Count.EqualTo(1));
|
||||
Assert.That(_queue.CurrentIndex, Is.EqualTo(0));
|
||||
Assert.That(raised, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearUpcoming_OnEmptyQueue_IsNoOpAndDoesNotRaiseQueueChanged()
|
||||
{
|
||||
var raised = false;
|
||||
_queue.QueueChanged += () => raised = true;
|
||||
|
||||
_queue.ClearUpcoming();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_queue.Items, Is.Empty);
|
||||
Assert.That(_queue.CurrentIndex, Is.EqualTo(-1));
|
||||
Assert.That(raised, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
// --- QueueChanged notifications ---
|
||||
|
||||
[Test]
|
||||
|
||||
Reference in New Issue
Block a user