diff options
Diffstat (limited to '')
| -rw-r--r-- | tests/queue.rs | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/tests/queue.rs b/tests/queue.rs index d338f2a..67cbabf 100644 --- a/tests/queue.rs +++ b/tests/queue.rs | |||
| @@ -567,6 +567,83 @@ fn test_shuffle_off_keeps_unplayed_duplicate_entries() { | |||
| 567 | assert_eq!(q.position(), 1); | 567 | assert_eq!(q.position(), 1); |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | #[test] | ||
| 571 | fn test_shuffle_play_now_current_is_inserted_track() { | ||
| 572 | // BUG: under shuffle, `insert_after_current` re-shuffles the tail | ||
| 573 | // (`update_shuffle_indices`), so the inserted track's play-order slot is a | ||
| 574 | // random draw instead of `position + 1`. The daemon's "now" flow (insert → | ||
| 575 | // `set_position(pos+1)` → play `track_at(position)`, src/daemon.rs) then | ||
| 576 | // starts the right file while `current()`/`next()`/the queue display | ||
| 577 | // follow a *different* track, and auto-advance can replay or skip the | ||
| 578 | // inserted track entirely. | ||
| 579 | // | ||
| 580 | // Contract: after the "now" sequence, `current()` must be the inserted | ||
| 581 | // track. The seed sweep keeps the test deterministic — for a fixed seed the | ||
| 582 | // outcome never varies between runs, and pre-fix a given seed satisfies the | ||
| 583 | // invariant with probability 1/(tail size) = 1/3, so the chance all 40 | ||
| 584 | // seeds accidentally pass is ~3e-19. The fix makes the invariant hold | ||
| 585 | // structurally (insert into the play order at `position+1`), independent | ||
| 586 | // of the seed. | ||
| 587 | let inserted = PathBuf::from("/music/new.mp3"); | ||
| 588 | for seed in 1..=40u64 { | ||
| 589 | let mut q = Queue::with_seed(seed); | ||
| 590 | add_track(&mut q, "/music/a.mp3"); | ||
| 591 | add_track(&mut q, "/music/b.mp3"); | ||
| 592 | add_track(&mut q, "/music/c.mp3"); | ||
| 593 | q.set_shuffle(ShuffleMode::All); | ||
| 594 | |||
| 595 | // `rsp play --now new.mp3` with a non-empty queue: insert after the | ||
| 596 | // current track and move the cursor onto it. | ||
| 597 | q.insert_after_current(inserted.clone()); | ||
| 598 | let new_pos = q.position() + 1; | ||
| 599 | q.set_position(new_pos); | ||
| 600 | |||
| 601 | assert_eq!(q.position(), 1); | ||
| 602 | let cur = q.current().expect("queue is not empty"); | ||
| 603 | assert_eq!( | ||
| 604 | cur.path, inserted, | ||
| 605 | "seed {}: current() after play-now is {:?}, expected {:?}; shuffled_indices={:?}", | ||
| 606 | seed, | ||
| 607 | cur.path, | ||
| 608 | inserted, | ||
| 609 | q.shuffled_indices() | ||
| 610 | ); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | // ---------- Seedable RNG ---------- | ||
| 615 | // The queue uses a seeded PRNG (rand::rngs::StdRng) instead of the OS-seeded | ||
| 616 | // thread RNG, so shuffle order is reproducible via Queue::with_seed. Shuffle | ||
| 617 | // is not a security domain — a PRNG suffices, and deterministic tests need a | ||
| 618 | // fixed seed. | ||
| 619 | |||
| 620 | #[test] | ||
| 621 | fn test_same_seed_produces_same_shuffle_order() { | ||
| 622 | let mut q1 = Queue::with_seed(0x5EED); | ||
| 623 | let mut q2 = Queue::with_seed(0x5EED); | ||
| 624 | for i in 0..10 { | ||
| 625 | add_track(&mut q1, &format!("/music/t{}.mp3", i)); | ||
| 626 | add_track(&mut q2, &format!("/music/t{}.mp3", i)); | ||
| 627 | } | ||
| 628 | q1.set_shuffle(ShuffleMode::All); | ||
| 629 | q2.set_shuffle(ShuffleMode::All); | ||
| 630 | assert_eq!(q1.shuffled_indices(), q2.shuffled_indices()); | ||
| 631 | } | ||
| 632 | |||
| 633 | #[test] | ||
| 634 | fn test_different_seed_produces_different_shuffle_order() { | ||
| 635 | let mut q1 = Queue::with_seed(1); | ||
| 636 | let mut q2 = Queue::with_seed(2); | ||
| 637 | for i in 0..20 { | ||
| 638 | add_track(&mut q1, &format!("/music/t{}.mp3", i)); | ||
| 639 | add_track(&mut q2, &format!("/music/t{}.mp3", i)); | ||
| 640 | } | ||
| 641 | q1.set_shuffle(ShuffleMode::All); | ||
| 642 | q2.set_shuffle(ShuffleMode::All); | ||
| 643 | // 20! permutations — identical order for two seeds is practically impossible. | ||
| 644 | assert_ne!(q1.shuffled_indices(), q2.shuffled_indices()); | ||
| 645 | } | ||
| 646 | |||
| 570 | // ---------- Track struct ---------- | 647 | // ---------- Track struct ---------- |
| 571 | 648 | ||
| 572 | #[test] | 649 | #[test] |
