diff options
author | Eddy Pedroni <epedroni@pm.me> | 2025-02-25 13:38:17 +0100 |
---|---|---|
committer | Eddy Pedroni <epedroni@pm.me> | 2025-02-25 13:38:17 +0100 |
commit | 62490ac2be04aa3b819222f11389e0549f5909e9 (patch) | |
tree | 1d8c79c3e1e0e1fc2fed71bdbcfcdf4ff97b2066 /solo-tool-project | |
parent | 876071a7a41ee4a1f579739b242a00058bdc160d (diff) |
Add song list notification, edge case tests
Diffstat (limited to 'solo-tool-project')
-rw-r--r-- | solo-tool-project/src/solo_tool/notifier.py | 5 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/solo_tool.py | 16 | ||||
-rw-r--r-- | solo-tool-project/test/solo_tool_songs_integrationtest.py (renamed from solo-tool-project/src/solo_tool/solo_tool_songs_integrationtest.py) | 111 |
3 files changed, 93 insertions, 39 deletions
diff --git a/solo-tool-project/src/solo_tool/notifier.py b/solo-tool-project/src/solo_tool/notifier.py index dadf85c..ac1c736 100644 --- a/solo-tool-project/src/solo_tool/notifier.py +++ b/solo-tool-project/src/solo_tool/notifier.py @@ -3,8 +3,9 @@ class Notifier: PLAYBACK_VOLUME_EVENT = 1 PLAYBACK_RATE_EVENT = 2 CURRENT_SONG_EVENT = 3 - CURRENT_KEY_POINT_EVENT = 3 - KEY_POINTS_EVENT = 4 + SONG_LIST_EVENT = 4 + CURRENT_KEY_POINT_EVENT = 5 + KEY_POINTS_EVENT = 6 def __init__(self, player): self._callbacks = dict() diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py index f5b05c0..bc20013 100644 --- a/solo-tool-project/src/solo_tool/solo_tool.py +++ b/solo-tool-project/src/solo_tool/solo_tool.py @@ -4,8 +4,8 @@ from .notifier import Notifier from .player_vlc import Player class SoloTool: - def __init__(self, playerOverride=None): - self._player = Player() if playerOverride is None else playerOverride + def __init__(self, player=None): + self._player = Player() if player is None else player self._notifier = Notifier(self._player) self._songs = [] self._song = None @@ -31,8 +31,11 @@ class SoloTool: def addSong(self, path: str) -> None: if not os.path.isfile(path): raise FileNotFoundError(path) + if path in self._songs: + return self._songs.append(path) self._keyPoints.append([]) + self._notifier.notify(Notifier.SONG_LIST_EVENT, self.songs) if self.song is None: self.song = 0 @@ -116,6 +119,12 @@ class SoloTool: if new is not None and new != self._player.getPlaybackPosition(): self._player.setPlaybackPosition(min(max(0.0, new), 1.0)) + def registerSongSelectionCallback(self, callback): + self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback) + + def registerSongListCallback(self, callback): + self._notifier.registerCallback(Notifier.SONG_LIST_EVENT, callback) + def registerPlayingStateCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback) @@ -125,9 +134,6 @@ class SoloTool: def registerRateCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYBACK_RATE_EVENT, callback) - def registerCurrentSongCallback(self, callback): - self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback) - def registerCurrentKeyPointCallback(self, callback): self._notifier.registerCallback(Notifier.CURRENT_KEY_POINT_EVENT, callback) diff --git a/solo-tool-project/src/solo_tool/solo_tool_songs_integrationtest.py b/solo-tool-project/test/solo_tool_songs_integrationtest.py index 0023d81..3d9368b 100644 --- a/solo-tool-project/src/solo_tool/solo_tool_songs_integrationtest.py +++ b/solo-tool-project/test/solo_tool_songs_integrationtest.py @@ -46,15 +46,15 @@ def test_songSelectionFlow(uut, mockPlayer, testSongs): assert uut.song == i assert mockPlayer.currentSong == uut.songs[i] -def test_songSelectionSanitization(uut, mockPlayer, testSongs): +def test_songSelectionEdgeCases(uut, mockPlayer, testSongs): + # When no songs are available, selecting has no effect + uut.song = 0 + assert uut.song == None + assert mockPlayer.currentSong == None + for song in testSongs: uut.addSong(song) - # Modifying the song list directly has no effect - uut.songs.append("something") - assert uut.songs == testSongs - assert mockPlayer.currentSong == testSongs[0] - # The current song cannot be de-selected uut.song = None assert uut.song == 0 @@ -69,44 +69,91 @@ def test_songSelectionSanitization(uut, mockPlayer, testSongs): assert uut.song == 0 assert mockPlayer.currentSong == testSongs[0] -def test_addInexistentSong(uut, mockPlayer): - # Songs must exist in the filesystem - song = "not/a/real/file" - - with pytest.raises(FileNotFoundError): +def test_songAdditionEdgeCases(uut, mockPlayer, testSongs): + for song in testSongs: uut.addSong(song) - assert uut.songs == [] - assert uut.song is None + # Modifying the song list directly has no effect + uut.songs.append("something") + assert uut.songs == testSongs + assert mockPlayer.currentSong == testSongs[0] + + # Same song cannot be added twice + uut.addSong(testSongs[0]) + assert uut.song == 0 + assert mockPlayer.currentSong == testSongs[0] + assert uut.songs == testSongs + + # Songs must exist in the filesystem + with pytest.raises(FileNotFoundError): + uut.addSong("/not/a/real/file") + assert uut.song == 0 + assert mockPlayer.currentSong == testSongs[0] + assert uut.songs == testSongs def test_songSelectionNotification(uut, testSongs): - called = False - receivedValue = None - def callback(value): - nonlocal called, receivedValue - called = True - receivedValue = value + selectionCalled = False + selectionValue = None + def selectionCallback(value): + nonlocal selectionCalled, selectionValue + selectionCalled = True + selectionValue = value - uut.registerSongSelectionCallback(callback) - assert not called + uut.registerSongSelectionCallback(selectionCallback) + assert not selectionCalled # Adding the first song triggers because the song is automatically selected - uut.addSong(songs[0]) - assert called - assert receivedValue == 0 - called = False + uut.addSong(testSongs[0]) - # Adding more songs does not trigger since the selection doesn't change - for song in testSongs: + assert selectionCalled + assert selectionValue == 0 + selectionCalled = False + + # Adding more songs does not trigger + for i, song in enumerate(testSongs[1:]): uut.addSong(song) - assert not called + assert not selectionCalled # Selecting another song triggers uut.song = 1 - assert called - assert receivedValue == 1 - called = False + assert selectionCalled + assert selectionValue == 1 + selectionCalled = False # Selecting the currently selected song does not trigger uut.song = 1 - assert not called + assert not selectionCalled + +def test_songListNotification(uut, testSongs): + listCalled = False + listValue = None + def listCallback(value): + nonlocal listCalled, listValue + listCalled = True + listValue = value + + uut.registerSongListCallback(listCallback) + assert not listCalled + + # Adding the first song triggers + uut.addSong(testSongs[0]) + + assert listCalled + assert listValue == testSongs[0:1] + listCalled = False + + # Adding more songs triggers + for i, song in enumerate(testSongs[1:]): + uut.addSong(song) + + assert listCalled + assert listValue == testSongs[0:i + 2] + listCalled = False + + # Modifying the list in place does not trigger + uut.songs.append("something") + assert not listCalled + + # Adding an existing song does not trigger + uut.addSong(testSongs[0]) + assert not listCalled |