From b97914699e1cb623e07766fb843b8cec1a07e375 Mon Sep 17 00:00:00 2001 From: Dustin Date: Tue, 4 Aug 2026 16:27:36 +0200 Subject: [PATCH] =?UTF-8?q?v2.48.5=20=E2=80=94=20Tests=20f=C3=BCr=20Player?= =?UTF-8?q?-Kern=20(Shuffle/Repeat/Queue/Sleep-Timer)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## test/player_service_test.dart (neu, 17 Tests) - Warteschlange: setWarteschlange, unveränderliche Kopie, spieleAlsNaechstes, amEndeHinzufuegen, verschiebeInWarteschlange (Index-Anpassung) - Repeat: aus (Ende → null), titel (immer aktuell), playlist (Wrap von vorn) - Shuffle: alle anderen Songs genau einmal ohne Wiederholung, kein aktueller Song; shuffle+playlist mischt nach Durchlauf neu; Einzel-Song-Queue; Ausschluss des aktuellen Index nach Umsortieren - Sleep-Timer: aktivieren, Restzeit, abbrechen, Ersetzen flutter analyze 0 Issues, Tests 21/21 --- test/player_service_test.dart | 187 ++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 test/player_service_test.dart diff --git a/test/player_service_test.dart b/test/player_service_test.dart new file mode 100644 index 0000000..06faf3d --- /dev/null +++ b/test/player_service_test.dart @@ -0,0 +1,187 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:melo_app/models/song.dart'; +import 'package:melo_app/services/player_service.dart'; + +Song _song(int id, String titel) => Song( + id: id, + titel: titel, + kuenstler: 'Künstler $id', + dauerSekunden: 100, + dateiPfad: '', +); + +void main() { + // PlayerService ist ein Singleton — Zustand vor jedem Test zurücksetzen + setUp(() { + final p = PlayerService(); + p.setZufallsmodus(false); + p.setWiederholmodus(Wiederholmodus.aus); + p.cancelSleepTimer(); + p.setWarteschlange([]); + }); + + group('Warteschlange', () { + test('setWarteschlange + Getter', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); + expect(p.warteschlange.length, 3); + expect(p.aktuellerIndex, 0); + expect(p.aktuellerSong?.titel, 'A'); + }); + + test('warteschlange ist eine unveränderliche Kopie', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B')]); + expect(() => p.warteschlange.add(_song(3, 'C')), throwsUnsupportedError); + expect(p.warteschlange.length, 2); + }); + + test('spieleAlsNaechstes fügt nach dem aktuellen Song ein', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); + p.spieleAlsNaechstes(_song(9, 'X')); + expect(p.warteschlange.map((s) => s.id).toList(), [1, 9, 2, 3]); + expect(p.aktuellerIndex, 0); + }); + + test('spieleAlsNaechstes ohne Warteschlange hängt an', () { + final p = PlayerService(); + p.spieleAlsNaechstes(_song(1, 'A')); + expect(p.warteschlange.length, 1); + expect(p.aktuellerIndex, -1); + }); + + test('amEndeHinzufuegen hängt ans Ende an', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A')]); + p.amEndeHinzufuegen(_song(2, 'B')); + expect(p.warteschlange.map((s) => s.id).toList(), [1, 2]); + }); + + test('verschiebeInWarteschlange passt aktuellen Index an (Song danach)', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); + p.verschiebeInWarteschlange(2, 0); // C nach vorne + expect(p.warteschlange.map((s) => s.id).toList(), [3, 1, 2]); + expect(p.aktuellerIndex, 1); // aktuell A (war 0, ist jetzt 1) + }); + + test('verschiebeInWarteschlange passt aktuellen Index an (Song davor)', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); + p.verschiebeInWarteschlange(0, 2); // aktueller Song selbst wandert + expect(p.warteschlange.map((s) => s.id).toList(), [2, 3, 1]); + expect(p.aktuellerIndex, 2); + }); + }); + + group('Repeat (Wiederholmodus)', () { + test('aus: naechsterIndex null am Ende der Warteschlange', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')], startIndex: 2); + p.setWiederholmodus(Wiederholmodus.aus); + expect(p.naechsterIndex(), isNull); + }); + + test('titel: immer der aktuelle Song', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')], startIndex: 1); + p.setWiederholmodus(Wiederholmodus.titel); + expect(p.naechsterIndex(), 1); + expect(p.naechsterIndex(), 1); + }); + + test('playlist: nach dem letzten Song wieder von vorn', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); + p.setWiederholmodus(Wiederholmodus.playlist); + // Mittendrin: nächster ist der Folgesong + expect(p.naechsterIndex(), 1); + // Am Ende (letzter Song): wieder von vorn + p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')], startIndex: 2); + expect(p.naechsterIndex(), 0); + }); + }); + + group('Shuffle (Zufallsmodus)', () { + test('spielt alle anderen Songs genau einmal, ohne den aktuellen', () { + final p = PlayerService(); + p.setWarteschlange([for (var i = 1; i <= 5; i++) _song(i, 'S$i')]); + p.setZufallsmodus(true); + final folge = []; + int? idx; + while ((idx = p.naechsterIndex()) != null) { + folge.add(idx!); + if (folge.length > 10) break; // Schutz vor Endlosschleife + } + expect(folge.length, 4); // 5 Songs − aktueller + expect(folge.toSet(), {1, 2, 3, 4}); // keine Wiederholung, kein aktueller + }); + + test('shuffle + playlist: mischt nach Durchlauf neu weiter', () { + final p = PlayerService(); + p.setWarteschlange([for (var i = 1; i <= 5; i++) _song(i, 'S$i')]); + p.setZufallsmodus(true); + p.setWiederholmodus(Wiederholmodus.playlist); + final folge = []; + for (var i = 0; i < 12; i++) { + final idx = p.naechsterIndex(); + expect(idx, isNotNull); + folge.add(idx!); + } + // Nie der aktuelle Song (Index 0), alle anderen kommen vor + expect(folge.every((i) => i >= 1 && i <= 4), isTrue); + expect(folge.toSet(), {1, 2, 3, 4}); + }); + + test('shuffle mit einzelner Warteschlange: playlist wiederholt den Song', () { + final p = PlayerService(); + p.setWarteschlange([_song(1, 'A')]); + p.setZufallsmodus(true); + p.setWiederholmodus(Wiederholmodus.playlist); + expect(p.naechsterIndex(), 0); + expect(p.naechsterIndex(), 0); + }); + + test('shuffle schließt neuen aktuellen Index nach Umsortieren aus', () { + final p = PlayerService(); + p.setWarteschlange([for (var i = 1; i <= 5; i++) _song(i, 'S$i')]); + p.setZufallsmodus(true); + p.verschiebeInWarteschlange(0, 2); // aktueller Song wandert auf Index 2 + expect(p.aktuellerIndex, 2); + final folge = []; + int? idx; + while ((idx = p.naechsterIndex()) != null) { + folge.add(idx!); + if (folge.length > 10) break; + } + expect(folge.toSet(), {0, 1, 3, 4}); // Index 2 (aktuell) nie dabei + }); + }); + + group('Sleep-Timer', () { + test('setSleepTimer aktiviert + Restzeit vorhanden', () { + final p = PlayerService(); + p.setSleepTimer(const Duration(minutes: 30)); + expect(p.sleepTimerAktiv, isTrue); + expect(p.sleepRestzeit, isNotNull); + expect(p.sleepRestzeit!.inMinutes, greaterThanOrEqualTo(29)); + }); + + test('cancelSleepTimer deaktiviert', () { + final p = PlayerService(); + p.setSleepTimer(const Duration(minutes: 15)); + p.cancelSleepTimer(); + expect(p.sleepTimerAktiv, isFalse); + expect(p.sleepRestzeit, isNull); + }); + + test('setSleepTimer ersetzt einen laufenden Timer', () { + final p = PlayerService(); + p.setSleepTimer(const Duration(minutes: 15)); + p.setSleepTimer(const Duration(minutes: 60)); + expect(p.sleepTimerAktiv, isTrue); + expect(p.sleepRestzeit!.inMinutes, greaterThanOrEqualTo(59)); + }); + }); +}