aboutsummaryrefslogtreecommitdiffstats
path: root/solo-tool-project
diff options
context:
space:
mode:
authorEddy Pedroni <epedroni@pm.me>2025-02-25 13:38:17 +0100
committerEddy Pedroni <epedroni@pm.me>2025-02-25 13:38:17 +0100
commit62490ac2be04aa3b819222f11389e0549f5909e9 (patch)
tree1d8c79c3e1e0e1fc2fed71bdbcfcdf4ff97b2066 /solo-tool-project
parent876071a7a41ee4a1f579739b242a00058bdc160d (diff)
Add song list notification, edge case tests
Diffstat (limited to 'solo-tool-project')
-rw-r--r--solo-tool-project/src/solo_tool/notifier.py5
-rw-r--r--solo-tool-project/src/solo_tool/solo_tool.py16
-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