From e7f97cc090331db1f53b55635c3daa564a9c330f Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:04:55 +0200 Subject: [PATCH] refactor(music): move the playback stub beside the tests that use it StubMusicPlaybackService is a base for test doubles with no production caller, so `check-unused-code lib` flagged it and the analysis job failed. Moves it to test/test_helpers/, where shared fakes belong. --- .../music/music_playback_service.dart | 143 ----------------- .../downloads_screen_focus_test.dart | 1 + .../music/album_detail_screen_test.dart | 1 + .../music/now_playing_screen_test.dart | 1 + test/screens/music/queue_sheet_test.dart | 1 + .../stub_music_playback_service.dart | 147 ++++++++++++++++++ test/widgets/media_context_menu_test.dart | 1 + test/widgets/music/mini_player_test.dart | 1 + 8 files changed, 153 insertions(+), 143 deletions(-) create mode 100644 test/test_helpers/stub_music_playback_service.dart diff --git a/lib/services/music/music_playback_service.dart b/lib/services/music/music_playback_service.dart index dcba1352..d73d433b 100644 --- a/lib/services/music/music_playback_service.dart +++ b/lib/services/music/music_playback_service.dart @@ -147,146 +147,3 @@ abstract class MusicPlaybackService extends ChangeNotifier { /// to `MediaServerClient.fetchLyrics`; null = none available. Future fetchLyrics(MediaItem track); } - -/// No-op base for test doubles, which override only the members under test. -/// Production always binds `MusicPlaybackServiceImpl`. -class StubMusicPlaybackService extends MusicPlaybackService { - final ValueNotifier _volumeNotifier = ValueNotifier(100); - int _playIntentGeneration = 0; - int _queueSessionRevision = 0; - - @override - MediaItem? get currentTrack => null; - - @override - MusicPlaybackStatus get status => MusicPlaybackStatus.idle; - - @override - Duration? get duration => null; - - @override - Duration get position => Duration.zero; - - @override - Stream get positionStream => const Stream.empty(); - - @override - List get queue => const []; - - @override - int get currentIndex => -1; - - @override - MusicPlayContext? get playContext => null; - - @override - bool get shuffled => false; - - @override - MusicRepeatMode get repeatMode => MusicRepeatMode.off; - - @override - Stream get errors => const Stream.empty(); - - @override - int beginPlayIntent() => ++_playIntentGeneration; - - @override - bool isPlayIntentCurrent(int intent) => intent == _playIntentGeneration; - - @override - int get queueSessionRevision => _queueSessionRevision; - - @override - Future playFromList({ - required List tracks, - MediaItem? startTrack, - required MusicPlayContext playContext, - bool shuffle = false, - }) async { - beginPlayIntent(); - _queueSessionRevision++; - } - - @override - Future playInstantMix(MediaItem seed) async {} - - @override - Future play() async {} - - @override - Future pause() async {} - - @override - Future togglePlayPause() async {} - - @override - Future next() async {} - - @override - Future previous() async {} - - @override - Future seek(Duration position) async {} - - @override - double get volume => 100; - @override - ValueListenable get volumeListenable => _volumeNotifier; - - @override - Future setVolume(double volume, {bool persist = true}) async {} - - @override - void setRepeatMode(MusicRepeatMode mode) {} - - @override - void toggleShuffle() {} - - @override - Future jumpTo(int index) async {} - - @override - void removeAt(int index) {} - - @override - void reorder(int from, int to) {} - - @override - void addNext(List tracks) {} - - @override - void addToEnd(List tracks) {} - - @override - void clearUpcoming() {} - - @override - Future stop() async { - beginPlayIntent(); - _queueSessionRevision++; - } - - @override - bool get sleepTimerActive => false; - - @override - DateTime? get sleepTimerEndsAt => null; - - @override - Duration? get sleepTimerDuration => null; - - @override - bool get sleepTimerEndOfTrack => false; - - @override - void setSleepTimer(Duration? duration, {bool endOfTrack = false}) {} - - @override - Future fetchLyrics(MediaItem track) async => null; - @override - void dispose() { - _volumeNotifier.dispose(); - super.dispose(); - } -} diff --git a/test/screens/downloads/downloads_screen_focus_test.dart b/test/screens/downloads/downloads_screen_focus_test.dart index 4d9189be..01765712 100644 --- a/test/screens/downloads/downloads_screen_focus_test.dart +++ b/test/screens/downloads/downloads_screen_focus_test.dart @@ -33,6 +33,7 @@ import '../../test_helpers/prefs.dart'; import '../../test_helpers/media_items.dart'; import '../../test_helpers/io_fakes.dart'; import '../../test_helpers/multi_server_fixtures.dart'; +import '../../test_helpers/stub_music_playback_service.dart'; class _FakeConnectionRegistry extends ConnectionRegistry { _FakeConnectionRegistry(super.db); diff --git a/test/screens/music/album_detail_screen_test.dart b/test/screens/music/album_detail_screen_test.dart index 48de3c1e..2dfd14f4 100644 --- a/test/screens/music/album_detail_screen_test.dart +++ b/test/screens/music/album_detail_screen_test.dart @@ -19,6 +19,7 @@ import 'package:provider/provider.dart'; import '../../test_helpers/prefs.dart'; import '../../test_helpers/media_items.dart'; import '../../test_helpers/multi_server_fixtures.dart'; +import '../../test_helpers/stub_music_playback_service.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/screens/music/now_playing_screen_test.dart b/test/screens/music/now_playing_screen_test.dart index 364fdd78..10c5036b 100644 --- a/test/screens/music/now_playing_screen_test.dart +++ b/test/screens/music/now_playing_screen_test.dart @@ -17,6 +17,7 @@ import 'package:provider/provider.dart'; import '../../test_helpers/media_items.dart'; import '../../test_helpers/multi_server_fixtures.dart'; +import '../../test_helpers/stub_music_playback_service.dart'; MediaItem _track({required String id, required String title, required String album, required int year}) { return testMediaItem( diff --git a/test/screens/music/queue_sheet_test.dart b/test/screens/music/queue_sheet_test.dart index 688e7e93..3e7bfc9a 100644 --- a/test/screens/music/queue_sheet_test.dart +++ b/test/screens/music/queue_sheet_test.dart @@ -17,6 +17,7 @@ import 'package:provider/provider.dart'; import '../../test_helpers/media_items.dart'; import '../../test_helpers/multi_server_fixtures.dart'; import '../../test_helpers/prefs.dart'; +import '../../test_helpers/stub_music_playback_service.dart'; MediaItem _track(String id, String title) => testMediaItem( id: id, diff --git a/test/test_helpers/stub_music_playback_service.dart b/test/test_helpers/stub_music_playback_service.dart new file mode 100644 index 00000000..244b62b1 --- /dev/null +++ b/test/test_helpers/stub_music_playback_service.dart @@ -0,0 +1,147 @@ +import 'package:flutter/foundation.dart'; +import 'package:plezy/media/lyrics.dart'; +import 'package:plezy/media/media_item.dart'; +import 'package:plezy/services/music/music_playback_service.dart'; + +/// No-op base for test doubles, which override only the members under test. +/// Production always binds `MusicPlaybackServiceImpl`. +class StubMusicPlaybackService extends MusicPlaybackService { + final ValueNotifier _volumeNotifier = ValueNotifier(100); + int _playIntentGeneration = 0; + int _queueSessionRevision = 0; + + @override + MediaItem? get currentTrack => null; + + @override + MusicPlaybackStatus get status => MusicPlaybackStatus.idle; + + @override + Duration? get duration => null; + + @override + Duration get position => Duration.zero; + + @override + Stream get positionStream => const Stream.empty(); + + @override + List get queue => const []; + + @override + int get currentIndex => -1; + + @override + MusicPlayContext? get playContext => null; + + @override + bool get shuffled => false; + + @override + MusicRepeatMode get repeatMode => MusicRepeatMode.off; + + @override + Stream get errors => const Stream.empty(); + + @override + int beginPlayIntent() => ++_playIntentGeneration; + + @override + bool isPlayIntentCurrent(int intent) => intent == _playIntentGeneration; + + @override + int get queueSessionRevision => _queueSessionRevision; + + @override + Future playFromList({ + required List tracks, + MediaItem? startTrack, + required MusicPlayContext playContext, + bool shuffle = false, + }) async { + beginPlayIntent(); + _queueSessionRevision++; + } + + @override + Future playInstantMix(MediaItem seed) async {} + + @override + Future play() async {} + + @override + Future pause() async {} + + @override + Future togglePlayPause() async {} + + @override + Future next() async {} + + @override + Future previous() async {} + + @override + Future seek(Duration position) async {} + + @override + double get volume => 100; + @override + ValueListenable get volumeListenable => _volumeNotifier; + + @override + Future setVolume(double volume, {bool persist = true}) async {} + + @override + void setRepeatMode(MusicRepeatMode mode) {} + + @override + void toggleShuffle() {} + + @override + Future jumpTo(int index) async {} + + @override + void removeAt(int index) {} + + @override + void reorder(int from, int to) {} + + @override + void addNext(List tracks) {} + + @override + void addToEnd(List tracks) {} + + @override + void clearUpcoming() {} + + @override + Future stop() async { + beginPlayIntent(); + _queueSessionRevision++; + } + + @override + bool get sleepTimerActive => false; + + @override + DateTime? get sleepTimerEndsAt => null; + + @override + Duration? get sleepTimerDuration => null; + + @override + bool get sleepTimerEndOfTrack => false; + + @override + void setSleepTimer(Duration? duration, {bool endOfTrack = false}) {} + + @override + Future fetchLyrics(MediaItem track) async => null; + @override + void dispose() { + _volumeNotifier.dispose(); + super.dispose(); + } +} diff --git a/test/widgets/media_context_menu_test.dart b/test/widgets/media_context_menu_test.dart index 3d6b4a53..74a36573 100644 --- a/test/widgets/media_context_menu_test.dart +++ b/test/widgets/media_context_menu_test.dart @@ -48,6 +48,7 @@ import '../test_helpers/media_items.dart'; import '../test_helpers/multi_server_fixtures.dart'; import '../test_helpers/prefs.dart'; import '../test_helpers/profile_stack.dart'; +import '../test_helpers/stub_music_playback_service.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/widgets/music/mini_player_test.dart b/test/widgets/music/mini_player_test.dart index 9f2f791d..46f1562a 100644 --- a/test/widgets/music/mini_player_test.dart +++ b/test/widgets/music/mini_player_test.dart @@ -27,6 +27,7 @@ import '../../test_helpers/media_items.dart'; import '../../test_helpers/multi_server_fixtures.dart'; import '../../test_helpers/prefs.dart'; import '../../test_helpers/profile_stack.dart'; +import '../../test_helpers/stub_music_playback_service.dart'; final _track = testMediaItem( id: 'track_1',