From bef8eee0f63cc5ccb963be9467381e4e605e7f53 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sat, 22 Feb 2025 22:59:52 +0100 Subject: Remove AB concept, introduce key points, refactor SoloTool to use properties --- solo-tool-project/src/solo_tool/abcontroller.py | 82 ---- solo-tool-project/src/solo_tool/notifier.py | 3 +- solo-tool-project/src/solo_tool/solo_tool.py | 167 ++++---- solo-tool-project/test/abcontroller_unittest.py | 272 ------------ .../test/midi_launchpad_mini_integrationtest.py | 120 ++---- solo-tool-project/test/notifier_unittest.py | 3 +- solo-tool-project/test/session_manager_unittest.py | 137 ++---- .../test/solo_tool_controller_integrationtest.py | 2 + .../test/solo_tool_integrationtest.py | 469 +++++++-------------- solo-tool-project/test/test_session.json | 7 +- 10 files changed, 306 insertions(+), 956 deletions(-) delete mode 100644 solo-tool-project/src/solo_tool/abcontroller.py delete mode 100644 solo-tool-project/test/abcontroller_unittest.py (limited to 'solo-tool-project') diff --git a/solo-tool-project/src/solo_tool/abcontroller.py b/solo-tool-project/src/solo_tool/abcontroller.py deleted file mode 100644 index cec9fb2..0000000 --- a/solo-tool-project/src/solo_tool/abcontroller.py +++ /dev/null @@ -1,82 +0,0 @@ -from collections import namedtuple - -_AB = namedtuple("_AB", ["a", "b"]) - -class ABController: - def __init__(self, enabled=True, callback=None): - self._setPositionCallback = callback - self._limits = {} # dictionary of all songs - self._songLimits = None # list of limits for selected song - self._currentLimits = _AB(0.0, 0.0) # a/b positions of active limit - self._loadedIndex = None - self._enabled = enabled - - def _ensureSongExists(self, path): - if path not in self._limits: - self._limits[path] = [] - - def setCurrentSong(self, path): - self._ensureSongExists(path) - self._songLimits = self._limits[path] - self._loadedIndex = None - - def storeLimits(self, aLimit, bLimit, song=None): - if song is not None: - self._ensureSongExists(song) - songLimits = self._limits[song] - else: - songLimits = self._songLimits - - if songLimits is None: - return - - ab = _AB(aLimit, bLimit) - songLimits.append(ab) - - def loadLimits(self, index): - if not self._songLimits: - return - - if index >= 0 and index < len(self._songLimits): - self._currentLimits = self._songLimits[index] - self._loadedIndex = index - - def nextStoredAbLimits(self): - if self._loadedIndex is None: - nextIndex = 0 - else: - nextIndex = self._loadedIndex + 1 - self.loadLimits(nextIndex) - - def previousStoredAbLimits(self): - if self._loadedIndex is None: - previousIndex = 0 - else: - previousIndex = self._loadedIndex - 1 - self.loadLimits(previousIndex) - - def setLimits(self, aLimit, bLimit): - self._currentLimits = _AB(aLimit, bLimit) - self._loadedIndex = None - - def positionChanged(self, position): - if position > self._currentLimits.b and self._setPositionCallback and self._enabled: - self._setPositionCallback(self._currentLimits.a) - - def setEnable(self, enable): - self._enabled = enable - - def isEnabled(self): - return self._enabled - - def getStoredLimits(self, song): - return self._limits.get(song) - - def getCurrentLimits(self): - return self._currentLimits - - def getLoadedIndex(self): - return self._loadedIndex - - def clear(self): - self.__init__(enabled=self._enabled, callback=self._setPositionCallback) diff --git a/solo-tool-project/src/solo_tool/notifier.py b/solo-tool-project/src/solo_tool/notifier.py index 9f445b6..73b84b7 100644 --- a/solo-tool-project/src/solo_tool/notifier.py +++ b/solo-tool-project/src/solo_tool/notifier.py @@ -3,8 +3,7 @@ class Notifier: PLAYBACK_VOLUME_EVENT = 1 PLAYBACK_RATE_EVENT = 2 CURRENT_SONG_EVENT = 3 - CURRENT_AB_EVENT = 4 - AB_LIMIT_ENABLED_EVENT = 5 + CURRENT_KEY_POINT_EVENT = 3 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 a4c7af8..884721b 100644 --- a/solo-tool-project/src/solo_tool/solo_tool.py +++ b/solo-tool-project/src/solo_tool/solo_tool.py @@ -1,6 +1,5 @@ import os -from .abcontroller import ABController from .session_manager import loadSession, saveSession from .notifier import Notifier from .player_vlc import Player @@ -8,32 +7,32 @@ from .player_vlc import Player class SoloTool: def __init__(self, playerOverride=None): self._player = Player() if playerOverride is None else playerOverride - self._abController = ABController(enabled=False, callback=self._abControllerCallback) self._notifier = Notifier(self._player) - self._songList = [] + self._songs = [] self._song = None + self._keyPoints = [] + self._keyPoint = None def _updateSong(self, index): self._song = index - path = self._songList[index] + path = self._songs[index] self._player.setCurrentSong(path) - self._abController.setCurrentSong(path) self._notifier.notify(Notifier.CURRENT_SONG_EVENT, index) + self._keyPoint = 0.0 - def _abControllerCallback(self, position): - self._player.setPlaybackPosition(position) - - def tick(self): - position = self._player.getPlaybackPosition() - self._abController.positionChanged(position) + @staticmethod + def _keyPointValid(kp: float) -> bool: + return kp is not None and kp >= 0.0 and kp < 1.0 @property - def songList(self) -> list[str]: - return self._songList + def songs(self) -> list[str]: + return self._songs.copy() def addSong(self, path: str) -> None: - if os.path.isfile(path): - self._songList.append(path) + if not os.path.isfile(path): + raise FileNotFoundError() + self._songs.append(path) + self._keyPoints.append([]) @property def song(self) -> int: @@ -41,64 +40,36 @@ class SoloTool: @song.setter def song(self, new: int) -> None: - if new >= 0 and new < len(self._songList) and new != self._song: + if new is None or new < 0 or new >= len(self._songs): + raise ValueError() + if new != self._song: self._updateSong(new) - def storeAbLimits(self, aLimit, bLimit): - self._abController.storeLimits(aLimit, bLimit) + @property + def keyPoints(self) -> list[float]: + if self._song is None: + return None + return self._keyPoints[self._song] + + @keyPoints.setter + def keyPoints(self, new: list[float]) -> None: + if new is None: + raise ValueError() + if self._song is not None: + sanitized = sorted(list(set([p for p in new if SoloTool._keyPointValid(p)]))) + self._keyPoints[self._song] = sanitized - def loadAbLimits(self, index): - previous = self._abController.getLoadedIndex() - self._abController.loadLimits(index) - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def setAbLimits(self, aLimit, bLimit): - self._abController.setLimits(aLimit, bLimit) + @property + def keyPoint(self) -> float: + return self._keyPoint - def getStoredAbLimits(self): - if self._song is not None: - return self._abController.getStoredLimits(self.songList[self._song]) - else: - return list() - - def setAbLimitEnable(self, enable): - previous = self._abController.isEnabled() - self._abController.setEnable(enable) - new = self._abController.isEnabled() - if previous != new: - self._notifier.notify(Notifier.AB_LIMIT_ENABLED_EVENT, new) - - def isAbLimitEnabled(self): - return self._abController.isEnabled() - - def nextStoredAbLimits(self): - previous = self._abController.getLoadedIndex() - self._abController.nextStoredAbLimits() - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def previousStoredAbLimits(self): - previous = self._abController.getLoadedIndex() - self._abController.previousStoredAbLimits() - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def jumpToA(self): - a = self._abController.getCurrentLimits()[0] - # XXX assumes that player.setPlaybackPosition is thread-safe! - self._player.setPlaybackPosition(a) - - def loadSession(self, path): - with open(path, "r") as f: - loadSession(f, self._songList, self._abController) - - def saveSession(self, path): - with open(path, "w") as f: - saveSession(f, self._songList, self._abController) + @keyPoint.setter + def keyPoint(self, new: float) -> None: + if not SoloTool._keyPointValid(new): + raise ValueError() + if self._song is not None and new != self._keyPoint: + self._keyPoint = new + self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, new) def play(self): self._player.play() @@ -112,43 +83,57 @@ class SoloTool: def isPlaying(self): return self._player.isPlaying() - def setPlaybackRate(self, rate): - previous = self._player.getPlaybackRate() - self._player.setPlaybackRate(rate) - new = self._player.getPlaybackRate() - if previous != new: - self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new) + def jump(self): + self._player.setPlaybackPosition(self._keyPoint) - def getPlaybackRate(self): + @property + def rate(self) -> float: return self._player.getPlaybackRate() - def setPlaybackPosition(self, position): - self._player.setPlaybackPosition(position) + @rate.setter + def rate(self, new: float) -> None: + if new is None or new <= 0.0: + raise ValueError() + if new != self._player.getPlaybackRate(): + self._player.setPlaybackRate(new) + self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new) + + @property + def volume(self) -> float: + return self._player.getPlaybackVolume() - def getPlaybackPosition(self): - return self._player.getPlaybackPosition() + @volume.setter + def volume(self, new: float) -> None: + if new is None or new < 0.0: + raise ValueError() + if new != self._player.getPlaybackVolume(): + self._player.setPlaybackVolume(new) + self._notifier.notify(Notifier.PLAYBACK_VOLUME_EVENT, new) - def setPlaybackVolume(self, volume): - self._player.setPlaybackVolume(volume) + @property + def position(self) -> float: + return self._player.getPlaybackPosition() - def getPlaybackVolume(self): - return self._player.getPlaybackVolume() + @position.setter + def position(self, new: float) -> None: + if new is None or new < 0.0 or new >= 1.0: + raise ValueError() + # TODO stop playback before changing position? + if new != self._player.getPlaybackPosition(): + self._player.setPlaybackPosition(new) def registerPlayingStateCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback) - def registerPlaybackVolumeCallback(self, callback): + def registerVolumeCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYBACK_VOLUME_EVENT, callback) - def registerPlaybackRateCallback(self, callback): + 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 registerCurrentAbLimitsCallback(self, callback): - self._notifier.registerCallback(Notifier.CURRENT_AB_EVENT, callback) - - def registerAbLimitEnabledCallback(self, callback): - self._notifier.registerCallback(Notifier.AB_LIMIT_ENABLED_EVENT, callback) + def registerCurrentKeyPointCallback(self, callback): + self._notifier.registerCallback(Notifier.CURRENT_KEY_POINT_EVENT, callback) diff --git a/solo-tool-project/test/abcontroller_unittest.py b/solo-tool-project/test/abcontroller_unittest.py deleted file mode 100644 index d2b7d31..0000000 --- a/solo-tool-project/test/abcontroller_unittest.py +++ /dev/null @@ -1,272 +0,0 @@ -from solo_tool.abcontroller import ABController -from collections import namedtuple - -TCase = namedtuple("TCase", ["currentPosition", "requestedPosition"]) -AB = namedtuple("AB", ["a", "b"]) -abLimits = AB(0.2, 0.4) - -def _checkLimits(uut, tests): - requestedPosition = None - def callback(newPosition): - nonlocal requestedPosition - requestedPosition = newPosition - - originalCallback = uut._setPositionCallback - uut._setPositionCallback = callback - - for t in tests: - uut.positionChanged(t.currentPosition) - assert requestedPosition == t.requestedPosition - - uut._setPositionCallback = originalCallback - -def checkLimits(uut, aLimit, bLimit, fail=False): - tests = [ - TCase(aLimit - 0.1, None), - TCase(aLimit, None), - TCase(bLimit - 0.1, None), - TCase(bLimit, None), - TCase(bLimit + 0.1, aLimit if not fail else None) - ] - _checkLimits(uut, tests) - if not fail: - assert uut.getCurrentLimits()[0] == aLimit - assert uut.getCurrentLimits()[1] == bLimit - -def checkDefaultLimits(uut): - tests = [ - TCase(0.0, None), - TCase(0.1, 0.0), - TCase(0.5, 0.0) - ] - _checkLimits(uut, tests) - -def test_oneSetOfLimits(): - song = "/path/to/song" - - uut = ABController() - uut.setCurrentSong(song) - uut.storeLimits(abLimits.a, abLimits.b) - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - checkLimits(uut, abLimits.a, abLimits.b) - assert uut.getStoredLimits(song) == [abLimits] - -def test_multipleSetsOfLimits(): - song = "/path/to/song" - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5), - AB(0.0, 1.2) - ] - - uut = ABController() - uut.setCurrentSong(song) - for l in abLimits: - uut.storeLimits(l.a, l.b) - - for i, l in enumerate(abLimits): - uut.loadLimits(i) - assert uut.getLoadedIndex() == i - checkLimits(uut, l.a, l.b) - - assert uut.getStoredLimits(song) == abLimits - -def test_multipleSongs(): - songs = [ - "/path/to/song", - "/path/to/another/song" - ] - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5) - ] - uut = ABController() - for i, s in enumerate(songs): - uut.storeLimits(abLimits[i].a, abLimits[i].b, s) - - for i, s in enumerate(songs): - uut.setCurrentSong(s) - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - checkLimits(uut, abLimits[i].a, abLimits[i].b) - assert uut.getStoredLimits(s) == [abLimits[i]] - -def test_disableAbRepeat(): - song = "/path/to/song" - - uut = ABController() - uut.setCurrentSong(song) - uut.storeLimits(abLimits.a, abLimits.b) - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - assert uut.isEnabled() - - uut.setEnable(False) - checkLimits(uut, abLimits.a, abLimits.b, fail=True) - assert not uut.isEnabled() - - uut.setEnable(True) - checkLimits(uut, abLimits.a, abLimits.b) - assert uut.isEnabled() - -def test_storeLimitsToSpecificSong(): - song = "/path/to/song" - - uut = ABController() - uut.storeLimits(abLimits.a, abLimits.b, song) - uut.setCurrentSong(song) - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - checkLimits(uut, abLimits.a, abLimits.b) - -def test_storeLimitsWithoutCurrentSong(): - uut = ABController() - uut.storeLimits(abLimits.a, abLimits.b) - uut.loadLimits(0) - assert uut.getLoadedIndex() == None - - checkDefaultLimits(uut) - -def test_storeLimitsToSongWithoutCurrentSong(): - song = "/path/to/song" - uut = ABController() - uut.storeLimits(abLimits.a, abLimits.b, song) - uut.loadLimits(0) - assert uut.getLoadedIndex() == None - - checkDefaultLimits(uut) - - uut.setCurrentSong(song) - - checkDefaultLimits(uut) - - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - checkLimits(uut, abLimits.a, abLimits.b) - -def test_storeLimitsToCurrentSongButDoNotSetCurrentLimits(): - song = "/path/to/song" - uut = ABController() - uut.setCurrentSong(song) - uut.storeLimits(abLimits.a, abLimits.b) - assert uut.getLoadedIndex() == None - - checkDefaultLimits(uut) - - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - checkLimits(uut, abLimits.a, abLimits.b) - -def test_getStoredLimitsOfInexistentSong(): - song = "/path/to/song" - uut = ABController() - assert uut.getStoredLimits(song) == None - -def test_clearAbController(): - songsWithLimits = [ - ("/path/to/song", AB(0.2, 0.4)), - ("/path/to/another/song", AB(0.3, 0.5)) - ] - - uut = ABController() - for s in songsWithLimits: - uut.storeLimits(s[1].a, s[1].b, s[0]) - - for i, s in enumerate(songsWithLimits): - assert uut.getStoredLimits(s[0]) == [s[1]] - - uut.clear() - - for i, s in enumerate(songsWithLimits): - assert uut.getStoredLimits(s[0]) == None - -def test_setTemporaryLimits(): - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5), - AB(0.0, 1.2) - ] - uut = ABController() - - for l in abLimits: - uut.setLimits(l.a, l.b) - assert uut.getLoadedIndex() == None - checkLimits(uut, l.a, l.b) - -def test_setTemporaryLimitsWithCurrentSong(): - songLimits = AB(0.2, 0.4) - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5), - AB(0.0, 1.2) - ] - song = "/path/to/song" - uut = ABController() - uut.setCurrentSong(song) - uut.storeLimits(songLimits.a, songLimits.b) - uut.loadLimits(0) - assert uut.getLoadedIndex() == 0 - - for l in abLimits: - uut.setLimits(l.a, l.b) - checkLimits(uut, l.a, l.b) - -def test_defaultBehaviour(): - uut = ABController() - checkDefaultLimits(uut) - -def test_nextStoredLimit(): - song = "/path/to/song" - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5) - ] - - uut = ABController() - uut.setCurrentSong(song) - for l in abLimits: - uut.storeLimits(l.a, l.b) - - checkDefaultLimits(uut) - - uut.nextStoredAbLimits() - checkLimits(uut, abLimits[0].a, abLimits[0].b) - - uut.nextStoredAbLimits() - checkLimits(uut, abLimits[1].a, abLimits[1].b) - - uut.nextStoredAbLimits() - checkLimits(uut, abLimits[1].a, abLimits[1].b) - -def test_previousStoredLimit(): - song = "/path/to/song" - abLimits = [ - AB(0.2, 0.4), - AB(0.3, 0.5) - ] - - uut = ABController() - uut.setCurrentSong(song) - for l in abLimits: - uut.storeLimits(l.a, l.b) - - checkDefaultLimits(uut) - - uut.previousStoredAbLimits() - checkLimits(uut, abLimits[0].a, abLimits[0].b) - - uut.previousStoredAbLimits() - checkLimits(uut, abLimits[0].a, abLimits[0].b) - - uut.loadLimits(1) - checkLimits(uut, abLimits[1].a, abLimits[1].b) - - uut.previousStoredAbLimits() - checkLimits(uut, abLimits[0].a, abLimits[0].b) diff --git a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py index c0d2b47..ec41ab2 100644 --- a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py +++ b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py @@ -1,6 +1,8 @@ import pytest from mido import Message +pytestmark = pytest.mark.skip(reason="not yet implemented") + from solo_tool.midi_controller_launchpad_mini import MidiController from solo_tool.solo_tool import SoloTool from player_mock import Player as PlayerMock @@ -22,12 +24,10 @@ previousSongButton = 48 playPauseButton = 112 stopButton = 96 -nextLimitButton = 119 -previousLimitButton = 118 -abToggleButton = 98 -jumpToAButton = 114 -setAButton = 116 -setBButton = 117 +nextKeyPositionButton = 119 +previousKeyPositionButton = 118 +setKeyPositionButton = 117 +jumpToKeyPositionButton = 114 class MidiWrapperMock: def __init__(self): @@ -120,35 +120,16 @@ def test_startPauseButtonLed(uut, midiWrapperMock, playerMock, soloTool): playerMock.simulatePlayingStateChanged() assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0) -def test_abToggleButton(uut, midiWrapperMock, soloTool): - uut.connect() - - midiWrapperMock.simulateInput(abToggleButton) - assert soloTool.isAbLimitEnabled() - assert midiWrapperMock.getLatestMessage() == (abToggleButton, MidiController.LED_GREEN, 0) - - midiWrapperMock.simulateInput(abToggleButton) - assert not soloTool.isAbLimitEnabled() - assert midiWrapperMock.getLatestMessage() == (abToggleButton, MidiController.LED_RED, 0) - -def test_abToggleButtonLed(uut, midiWrapperMock, soloTool): - uut.connect() - - soloTool.setAbLimitEnable(True) - assert midiWrapperMock.getLatestMessage() == (abToggleButton, MidiController.LED_GREEN, 0) - - soloTool.setAbLimitEnable(False) - assert midiWrapperMock.getLatestMessage() == (abToggleButton, MidiController.LED_RED, 0) - -def test_jumpToAButton(uut, midiWrapperMock, soloTool, playerMock): - ab = (0.5, 0.6) +def test_jumpToKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock): + soloTool.addSong("test.flac") + soloTool.song = 0 uut.connect() - soloTool.setAbLimits(ab[0], ab[1]) + soloTool.keyPosition = 0.5 assert playerMock.position == 0.0 - midiWrapperMock.simulateInput(jumpToAButton) - assert playerMock.position == ab[0] + midiWrapperMock.simulateInput(jumpToKeyPositionButton) + assert playerMock.position == 0.5 def test_previousAndNextSongButtons(uut, midiWrapperMock, soloTool, playerMock): songs = [ @@ -172,47 +153,29 @@ def test_previousAndNextSongButtons(uut, midiWrapperMock, soloTool, playerMock): midiWrapperMock.simulateInput(previousSongButton) assert playerMock.currentSong == songs[0] -def test_previousAndNextAbButtons(uut, midiWrapperMock, soloTool, playerMock): +def test_previousAndNextKeyPositionButtons(uut, midiWrapperMock, soloTool, playerMock): song = "test.flac" - abLimits = [ - [0.2, 0.4], - [0.1, 0.3] - ] + keyPositions = [0.2, 0.1] soloTool.addSong(song) soloTool.song = 0 - soloTool.setAbLimitEnable(True) - - for ab in abLimits: - soloTool.storeAbLimits(ab[0], ab[1]) + soloTool.keyPositions = keyPositions uut.connect() - def checkLimit(aLimit, bLimit): - playerMock.position = bLimit - 0.1 - soloTool.tick() - assert playerMock.position == bLimit - 0.1 - - playerMock.position = bLimit + 0.1 - soloTool.tick() - assert playerMock.position == aLimit - - checkLimit(0.0, 0.0) - - midiWrapperMock.simulateInput(nextLimitButton) - checkLimit(abLimits[0][0], abLimits[0][1]) + assert soloTool.keyPosition == 0.0 - midiWrapperMock.simulateInput(nextLimitButton) - checkLimit(abLimits[1][0], abLimits[1][1]) + midiWrapperMock.simulateInput(nextKeyPositionButton) + soloTool.keyPosition == 0.1 - midiWrapperMock.simulateInput(nextLimitButton) - checkLimit(abLimits[1][0], abLimits[1][1]) + midiWrapperMock.simulateInput(nextKeyPositionButton) + soloTool.keyPosition == 0.2 - midiWrapperMock.simulateInput(previousLimitButton) - checkLimit(abLimits[0][0], abLimits[0][1]) + midiWrapperMock.simulateInput(previousKeyPositionButton) + soloTool.keyPosition == 0.1 - midiWrapperMock.simulateInput(previousLimitButton) - checkLimit(abLimits[0][0], abLimits[0][1]) + midiWrapperMock.simulateInput(previousKeyPositionButton) + soloTool.keyPosition == 0.1 def test_playbackRateButtons(uut, midiWrapperMock, soloTool, playerMock): playbackRateOptions = { @@ -406,41 +369,24 @@ def test_playingFeedbackWhenChangingSong(uut, midiWrapperMock, soloTool, playerM assert playerMock.state == PlayerMock.STOPPED assert midiWrapperMock.getLatestMessage() == (playPauseButton, LED_YELLOW, 0) -def test_setAbButtons(uut, midiWrapperMock, soloTool, playerMock): +def test_setKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock): song = "test.flac" soloTool.addSong(song) soloTool.song = 0 - soloTool.setAbLimitEnable(True) - abLimits = (0.6, 0.8) - soloTool.storeAbLimits(abLimits[0], abLimits[1]) uut.connect() - def checkLimit(aLimit, bLimit): - playerMock.position = bLimit - 0.1 - soloTool.tick() - assert playerMock.position == bLimit - 0.1 - - playerMock.position = bLimit + 0.1 - soloTool.tick() - assert playerMock.position == aLimit - - # Set A limit playerMock.position = 0.3 - midiWrapperMock.simulateInput(setAButton) - playerMock.position = 0.5 - midiWrapperMock.simulateInput(jumpToAButton) + midiWrapperMock.simulateInput(setKeyPositionButton) + assert soloTool.keyPosition == 0.3 - assert playerMock.position == 0.3 - - # Set B limit - playerMock.position = 0.4 - midiWrapperMock.simulateInput(setBButton) - checkLimit(0.3, 0.4) + playerMock.position = 0.5 + midiWrapperMock.simulateInput(setKeyPositionButton) + assert soloTool.keyPosition == 0.5 - # Selecting preset overrides manually set limits - midiWrapperMock.simulateInput(nextLimitButton) - checkLimit(abLimits[0], abLimits[1]) + playerMock.position = 0.7 + midiWrapperMock.simulateInput(jumpToKeyPositionButton) + assert playerMock.position == 0.5 def test_seekButtons(uut, midiWrapperMock, soloTool, playerMock): song = "test.flac" diff --git a/solo-tool-project/test/notifier_unittest.py b/solo-tool-project/test/notifier_unittest.py index 8a6e988..115d21a 100644 --- a/solo-tool-project/test/notifier_unittest.py +++ b/solo-tool-project/test/notifier_unittest.py @@ -37,8 +37,7 @@ def test_allEvents(uut): checkEvent(uut, Notifier.PLAYBACK_VOLUME_EVENT) checkEvent(uut, Notifier.PLAYBACK_RATE_EVENT) checkEvent(uut, Notifier.CURRENT_SONG_EVENT) - checkEvent(uut, Notifier.CURRENT_AB_EVENT) - checkEvent(uut, Notifier.AB_LIMIT_ENABLED_EVENT) + checkEvent(uut, Notifier.CURRENT_KEY_POINT_EVENT) def test_eventWithoutRegisteredCallbacks(uut): uut.notify(Notifier.PLAYING_STATE_EVENT, 0) diff --git a/solo-tool-project/test/session_manager_unittest.py b/solo-tool-project/test/session_manager_unittest.py index e74bab4..0edc252 100644 --- a/solo-tool-project/test/session_manager_unittest.py +++ b/solo-tool-project/test/session_manager_unittest.py @@ -1,114 +1,59 @@ -from solo_tool.session_manager import loadSession, saveSession -from json import loads, dumps - import pytest +from json import loads +import pathlib +import shutil -testSession = [ - { - "path" : "/path/to/another/song", - "ab_limits" : None - }, - { - "path" : "/path/to/song", - "ab_limits" : [ - [0.1, 0.2], - [0.3, 0.4] - ] - }, - { - "path" : "/path/to/something", - "ab_limits" : [ - [0.1, 0.2] - ] - } -] - -class ABControllerMock: - def __init__(self): - self.limits = dict() - - def storeLimits(self, aLimit, bLimit, song="current"): - if song not in self.limits: - self.limits[song] = list() - self.limits[song].append([aLimit, bLimit]) - - def getStoredLimits(self, song): - return self.limits.get(song) - - def clear(self): - self.__init__() - -class MockFile: - def __init__(self, init=""): - self.contents = init - - def open(self, *args): - pass - - def write(self, s): - self.contents += s +pytestmark = pytest.mark.skip(reason="not yet implemented") - def read(self): - return self.contents - -@pytest.fixture -def songListMock(): - return [] +from solo_tool.session_manager import loadSession, saveSession +from solo_tool.solo_tool import SoloTool @pytest.fixture -def abControllerMock(): - return ABControllerMock() +def prepared_tmp_path(tmp_path): + testFiles = [ + "test.flac", + "test.mp3", + "test_session.json" + ] + for f in testFiles: + shutil.copy(pathlib.Path(f), tmp_path) + return tmp_path -def test_loadSession(songListMock, abControllerMock): - sessionFile = MockFile(dumps(testSession)) - loadSession(sessionFile, songListMock, abControllerMock) +def test_loadSession(prepared_tmp_path): + soloTool = loadSession(prepared_tmp_path / "test_session.json") - for i, entry in enumerate(testSession): - expectedSong = entry["path"] - expectedLimits = entry["ab_limits"] - loadedSong = songListMock[i] - loadedLimits = abControllerMock.limits.get(expectedSong) + assert soloTool.songs == ["test.flac", "test.mp3"] - assert loadedSong == expectedSong - assert loadedLimits == expectedLimits + soloTool.song = 0 + assert soloTool.keyPositions == [] -def test_saveSession(songListMock, abControllerMock): - for i, entry in enumerate(testSession): - song = entry["path"] - songListMock.append(song) + soloTool.song = 1 + assert soloTool.keyPositions == [0.1, 0.3] - abLimits = entry["ab_limits"] - if abLimits is not None: - for l in abLimits: - abControllerMock.storeLimits(l[0], l[1], song) +def test_saveSession(prepared_tmp_path): + soloTool = SoloTool() + soloTool.addSong("test.flac") + soloTool.addSong("test.mp3") + soloTool.keyPositions = [0.1, 0.3] - sessionFile = MockFile() - saveSession(sessionFile, songListMock, abControllerMock) + testFile = prepared_tmp_path / "test_session_saved.json" + saveSession(soloTool, testFile) - savedSession = loads(sessionFile.read()) - assert savedSession == testSession + with open(testFile, "r") as f: + savedSession = loads(f.read()) -def test_loadAndSaveEmptySession(songListMock, abControllerMock): - sessionFile = MockFile() + with open(prepared_tmp_path / "test_session.json", "r") as f: + testSession = loads(f.read()) - saveSession(sessionFile, songListMock, abControllerMock) - assert loads(sessionFile.read()) == list() + assert savedSession == testSession - loadSession(sessionFile, songListMock, abControllerMock) +def test_loadAndSaveEmptySession(prepared_tmp_path): + emptyFile = prepared_tmp_path / "empty_session.json" - assert songListMock == list() - for s in songListMock: - assert abControllerMock.getStoredLimits(s) == None + soloTool = SoloTool() -def test_loadSessionNotAdditive(songListMock, abControllerMock): - sessionFile = MockFile(dumps(testSession)) - loadSession(sessionFile, songListMock, abControllerMock) - loadSession(sessionFile, songListMock, abControllerMock) + saveSession(soloTool, emptyFile) + reloadedTool = loadSession(emptyFile) - songs = songListMock - assert len(songs) == len(set(songs)) - for s in songs: - abLimits = abControllerMock.getStoredLimits(s) - if abLimits is not None: - abLimitStr = [f"[{l[0]}, {l[1]}] " for l in abLimits] - assert len(abLimitStr) == len(set(abLimitStr)) + assert reloadedTool.songs == [] + diff --git a/solo-tool-project/test/solo_tool_controller_integrationtest.py b/solo-tool-project/test/solo_tool_controller_integrationtest.py index 9311483..e39e5f9 100644 --- a/solo-tool-project/test/solo_tool_controller_integrationtest.py +++ b/solo-tool-project/test/solo_tool_controller_integrationtest.py @@ -2,6 +2,8 @@ import pathlib import shutil import pytest +pytestmark = pytest.mark.skip(reason="not yet implemented") + from solo_tool.solo_tool_controller import SoloToolController from solo_tool.solo_tool import SoloTool diff --git a/solo-tool-project/test/solo_tool_integrationtest.py b/solo-tool-project/test/solo_tool_integrationtest.py index 3a15e36..94d5cef 100644 --- a/solo-tool-project/test/solo_tool_integrationtest.py +++ b/solo-tool-project/test/solo_tool_integrationtest.py @@ -25,15 +25,6 @@ def prepared_tmp_path(tmp_path): return tmp_path -def checkLimit(uut, mockPlayer, aLimit, bLimit): - mockPlayer.position = bLimit - 0.1 - uut.tick() - assert mockPlayer.position == bLimit - 0.1 - - mockPlayer.position = bLimit + 0.1 - uut.tick() - assert mockPlayer.position == aLimit - def test_playerControls(uut, mockPlayer): assert mockPlayer.state == MockPlayer.STOPPED assert uut.isPlaying() == False @@ -48,306 +39,189 @@ def test_playerControls(uut, mockPlayer): assert uut.isPlaying() == False assert mockPlayer.rate == 1.0 - uut.setPlaybackRate(0.5) + uut.rate = 0.5 assert mockPlayer.rate == 0.5 + assert uut.rate == 0.5 assert mockPlayer.position == 0.0 - uut.setPlaybackPosition(0.5) + uut.position = 0.5 assert mockPlayer.position == 0.5 + assert uut.position == 0.5 assert mockPlayer.volume == 1.0 - uut.setPlaybackVolume(0.5) + uut.volume = 0.5 assert mockPlayer.volume == 0.5 + assert uut.volume == 0.5 -def test_addAndSetSongs(uut, mockPlayer): - songs = [ - "test.flac", - "test.mp3" - ] +def test_sanitizePlaybackRate(uut): + # Valid rates are > 0.0 + with pytest.raises(ValueError): + uut.rate = -0.1 - for s in songs: - uut.addSong(s) - assert mockPlayer.currentSong == None - - for i, s in enumerate(songs): - uut.song = i - assert mockPlayer.currentSong == songs[i] - assert uut.song == i + with pytest.raises(ValueError): + uut.rate = 0.0 -def test_addAndSetAbLimits(uut, mockPlayer): - song = "test.flac" - abLimits = [ - [0.2, 0.4], - [0.1, 0.3] - ] + uut.rate = 1.0 + uut.rate = 150.0 - uut.addSong(song) - uut.song = 0 +def test_sanitizePlaybackPosition(uut): + # Valid positions are in [0, 1) + with pytest.raises(ValueError): + uut.position = -0.1 - for ab in abLimits: - uut.storeAbLimits(ab[0], ab[1]) + uut.position = 0.0 + uut.position = 0.999 - mockPlayer.position = 0.0 - uut.tick() - assert mockPlayer.position == 0.0 + with pytest.raises(ValueError): + uut.position = 1.0 - mockPlayer.position = 0.5 - uut.tick() - assert mockPlayer.position == 0.5 +def test_sanitizePlaybackVolume(uut): + # Valid volumes are >= 0.0 + with pytest.raises(ValueError): + uut.volume = -0.1 - uut.loadAbLimits(0) + uut.volume = 0.0 + uut.volume = 1.0 + uut.volume = 150.0 - uut.tick() - assert mockPlayer.position == 0.5 +def test_addAndSelectSongs(uut, mockPlayer): + songs = [ + "test.mp3", + "test.flac" + ] - uut.setAbLimitEnable(True) + # Songs are added one by one + for song in songs: + uut.addSong(song) - uut.tick() - assert mockPlayer.position == 0.2 + # Songs are not selected automatically + assert mockPlayer.currentSong == None + assert uut.song == None - uut.tick() - assert mockPlayer.position == 0.2 + # Song order is preserved + assert uut.songs == songs - uut.loadAbLimits(1) - uut.tick() - assert mockPlayer.position == 0.2 + # Modifying the song list directly has no effect + uut.songs.append("something") + assert uut.songs == songs - mockPlayer.position = 0.8 - uut.tick() - assert mockPlayer.position == 0.1 + # Songs are selected by index + for i, s in enumerate(uut.songs): + uut.song = i + assert mockPlayer.currentSong == uut.songs[i] + assert uut.song == i -def test_abLimitEnabledGetter(uut): - assert not uut.isAbLimitEnabled() + # The current song cannot be de-selected + with pytest.raises(ValueError): + uut.song = None + assert uut.song == len(uut.songs) - 1 - uut.setAbLimitEnable(True) - assert uut.isAbLimitEnabled() + # Non-existent songs cannot be selected + with pytest.raises(ValueError): + uut.song = -1 + assert uut.song == len(uut.songs) - 1 - uut.setAbLimitEnable(False) - assert not uut.isAbLimitEnabled() + with pytest.raises(ValueError): + uut.song = 2 + assert uut.song == len(uut.songs) - 1 -def test_multipleSongsAndAbLimits(uut, mockPlayer): - songs = [ - "test.flac", - "test.mp3" - ] - abLimits = [ - [0.2, 0.4], - [0.5, 0.7] - ] - - for s in songs: - uut.addSong(s) +def test_addAndJumpToKeyPoints(uut, mockPlayer): + uut.addSong("test.flac") + uut.addSong("test.mp3") - for i, l in enumerate(abLimits): - uut.song = i - uut.storeAbLimits(l[0], l[1]) + def checkJump(before, expectedAfter): + mockPlayer.position = before + uut.jump() + assert mockPlayer.position == expectedAfter - uut.setAbLimitEnable(True) - - for i, l in enumerate(abLimits): - uut.song = i - uut.loadAbLimits(0) + # Key points are None as long as no song is selected + uut.keyPoints = [0.1, 0.2] + uut.keyPoint = 0.5 + assert uut.keyPoints is None + assert uut.keyPoint is None - mockPlayer.position = l[0] - uut.tick() - assert mockPlayer.position == l[0] - - mockPlayer.position = l[1] + 0.1 - uut.tick() - assert mockPlayer.position == l[0] - -def test_storeAbLimitsWithoutSong(uut, mockPlayer): - song = "test.flac" - abLimit = [0.2, 0.4] - overflow = abLimit[1] + 0.1 - default = 0.0 - mockPlayer.position = overflow - uut.setAbLimitEnable(True) - - uut.storeAbLimits(abLimit[0], abLimit[1]) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow - - uut.loadAbLimits(0) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + uut.song = 0 - uut.addSong(song) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + # Once a song is selected, jump to start by default + assert uut.keyPoint == 0.0 + checkJump(0.5, 0.0) - uut.loadAbLimits(0) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + # By default songs have an empty list of key points + assert uut.keyPoints == [] - uut.song = 0 - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + uut.keyPoints = [0.2, 0.4, 0.1, 0.2] - uut.loadAbLimits(0) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + # Added key points are not automatically selected + assert uut.keyPoint == 0.0 + checkJump(0.1, 0.0) - uut.storeAbLimits(abLimit[0], abLimit[1]) - uut.tick() - assert mockPlayer.position == default - mockPlayer.position = overflow + # Any key point can be selected + uut.keyPoint = uut.keyPoints[0] + checkJump(0.0, uut.keyPoints[0]) - uut.loadAbLimits(0) - uut.tick() - assert mockPlayer.position == abLimit[0] + uut.keyPoint = 0.5 + checkJump(0.0, 0.5) -def test_nextAndPreviousAbLimit(uut, mockPlayer): +def test_sanitizeKeyPoint(uut): song = "test.flac" - abLimits = [ - [0.2, 0.4], - [0.1, 0.3] - ] - uut.addSong(song) uut.song = 0 - uut.setAbLimitEnable(True) + uut.keyPoints = [0.2, 0.4, 0.1, 0.2, None, -0.5, 1.0, 1.5] - for ab in abLimits: - uut.storeAbLimits(ab[0], ab[1]) + # Added key points are automatically de-duplicated, sanitized and sorted to ascending order + assert uut.keyPoints == [0.1, 0.2, 0.4] - checkLimit(uut, mockPlayer, 0.0, 0.0) # default limits + # Key point and key point list cannot be none + uut.keyPoint = 0.5 - uut.nextStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[0][0], abLimits[0][1]) + with pytest.raises(ValueError): + uut.keyPoint = None + assert uut.keyPoint == 0.5 - uut.nextStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[1][0], abLimits[1][1]) + with pytest.raises(ValueError): + uut.keyPoints = None + assert uut.keyPoints == [0.1, 0.2, 0.4] - uut.nextStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[1][0], abLimits[1][1]) + # Valid key points are in [0, 1) + with pytest.raises(ValueError): + uut.keyPoint = -0.1 - uut.previousStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[0][0], abLimits[0][1]) + with pytest.raises(ValueError): + uut.keyPoint = 1.0 - uut.previousStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[0][0], abLimits[0][1]) + uut.keyPoint = 0.999 -def test_abLimitsWhenChangingSongs(uut, mockPlayer): +def test_keyPointsPerSong(uut, mockPlayer): songs = [ - "test.flac", - "test.mp3" - ] - abLimits = [ - [0.2, 0.4], - [0.1, 0.3], - [0.7, 0.8] + ("test.flac", [0.0, 0.5]), + ("test.mp3", [0.1]) ] - uut.setAbLimitEnable(True) - - for s in songs: - uut.addSong(s) - - uut.song = 0 - for ab in abLimits: - uut.storeAbLimits(ab[0], ab[1]) - - uut.song = 1 - uut.storeAbLimits(abLimits[0][0], abLimits[0][1]) - - uut.song = 0 - uut.loadAbLimits(len(abLimits) - 1) - checkLimit(uut, mockPlayer, abLimits[-1][0], abLimits[-1][1]) - - uut.song = 1 - checkLimit(uut, mockPlayer, abLimits[-1][0], abLimits[-1][1]) - - uut.previousStoredAbLimits() - checkLimit(uut, mockPlayer, abLimits[0][0], abLimits[0][1]) -def test_loadAndSaveSession(prepared_tmp_path): - mockPlayer = MockPlayer() - uut = SoloTool(mockPlayer) - - loadedSessionFile = prepared_tmp_path / "test_session.json" - savedSessionFile = prepared_tmp_path / "test_session_save.json" - - uut.loadSession(loadedSessionFile) - uut.saveSession(savedSessionFile) + # Key points list is set for the selected song + for i, (song, keyPoints) in enumerate(songs): + uut.addSong(song) + uut.song = i + uut.keyPoints = keyPoints - import json - with open(loadedSessionFile, "r") as f: - loadedSession = json.loads(f.read()) - - with open(savedSessionFile, "r") as f: - savedSession = json.loads(f.read()) + # Key points list is automatically loaded when the song selection changes + # Active key point is always reset to 0 when song selection changes + for i, (song, keyPoints) in enumerate(songs): + uut.keyPoint = 0.5 + uut.song = i + assert uut.keyPoints == keyPoints + assert uut.keyPoint == 0.0 - assert loadedSession == savedSession + # Key points are copied, not stored by reference + for i, (song, keyPoints) in enumerate(songs): + uut.song = i + keyPoints.append(1.0) + assert 1.0 not in uut.keyPoints -def test_addInexistentFile(uut, mockPlayer): +def test_addInexistentSong(uut, mockPlayer): song = "not/a/real/file" - uut.addSong(song) - uut.song = 0 - - assert mockPlayer.currentSong == None - -def test_getters(uut, mockPlayer): - song = "test.flac" - abLimit = [0.2, 0.4] - - uut.addSong(song) - uut.song = 0 - uut.storeAbLimits(abLimit[0], abLimit[1]) - - assert uut.songList == [song] - - limits = uut.getStoredAbLimits() - assert len(limits) == 1 - assert limits[0][0] == abLimit[0] - assert limits[0][1] == abLimit[1] - - mockPlayer.position = 0.8 - assert uut.getPlaybackPosition() == 0.8 - - mockPlayer.volume = 0.8 - assert uut.getPlaybackVolume() == 0.8 - - mockPlayer.rate = 0.5 - assert uut.getPlaybackRate() == 0.5 - -def test_setTemporaryLimits(uut, mockPlayer): - song = "test.flac" - abLimits = [ - [0.2, 0.4], - [0.1, 0.4] - ] - overflow = 0.5 - - uut.setAbLimitEnable(True) - mockPlayer.position = overflow - uut.addSong(song) - uut.song = 0 - uut.storeAbLimits(abLimits[0][0], abLimits[0][1]) - uut.loadAbLimits(0) - - uut.setAbLimits(abLimits[1][0], abLimits[1][1]) - uut.tick() - assert mockPlayer.position == abLimits[1][0] - -def test_jumpToA(uut, mockPlayer): - abLimits = (0.2, 0.4) - initialPosition = 0.8 - - mockPlayer.position = initialPosition - - uut.jumpToA() - assert mockPlayer.position == 0.0 # default AB controller A limit - - uut.setAbLimits(abLimits[0], abLimits[1]) - uut.jumpToA() - assert mockPlayer.position == abLimits[0] + with pytest.raises(FileNotFoundError): + uut.addSong(song) def test_playingStateNotification(uut, mockPlayer): song = "test.flac" @@ -404,16 +278,16 @@ def test_playbackVolumeNotification(uut, mockPlayer): called = True receivedValue = value - uut.registerPlaybackVolumeCallback(callback) + uut.registerVolumeCallback(callback) assert not called - uut.setPlaybackVolume(0.3) + uut.volume = 0.3 assert called assert receivedValue == 0.3 called = False - uut.setPlaybackVolume(0.3) + uut.volume = 0.3 assert not called def test_playbackRateNotification(uut, mockPlayer): @@ -428,16 +302,16 @@ def test_playbackRateNotification(uut, mockPlayer): called = True receivedValue = value - uut.registerPlaybackRateCallback(callback) + uut.registerRateCallback(callback) assert not called - uut.setPlaybackRate(0.5) + uut.rate = 0.5 assert called assert receivedValue == 0.5 called = False - uut.setPlaybackRate(0.5) + uut.rate = 0.5 assert not called def test_currentSongNotification(uut): @@ -455,9 +329,12 @@ def test_currentSongNotification(uut): "test.flac", "test.mp3" ] + + # Adding a song does not trigger a notification uut.addSong(songs[0]) assert not called + # Selecting a song for the first time triggers uut.song = 0 assert called assert receivedValue == 0 @@ -466,6 +343,7 @@ def test_currentSongNotification(uut): uut.addSong(songs[1]) assert not called + # Selecting the same song does not trigger uut.song = 0 assert not called @@ -474,7 +352,7 @@ def test_currentSongNotification(uut): assert receivedValue == 1 called = False -def test_currentAbNotification(uut): +def test_currentKeyPointNotification(uut): called = False receivedValue = None def callback(value): @@ -482,76 +360,29 @@ def test_currentAbNotification(uut): called = True receivedValue = value - uut.registerCurrentAbLimitsCallback(callback) + uut.registerCurrentKeyPointCallback(callback) assert not called song = "test.flac" uut.addSong(song) uut.song = 0 - abLimits = [ - (0.2, 0.3), - (0.4, 0.5) - ] - uut.storeAbLimits(abLimits[0][0], abLimits[0][1]) - assert not called - uut.storeAbLimits(abLimits[1][0], abLimits[1][1]) - assert not called - - uut.loadAbLimits(0) - assert called - assert receivedValue == 0 - called = False - - uut.loadAbLimits(0) - assert not called - - uut.loadAbLimits(1) + # Selecting a song for the first time sets the key point to 0.0 assert called - assert receivedValue == 1 + assert receivedValue == 0.0 called = False - uut.previousStoredAbLimits() + # Changing the key point triggers a notification + uut.keyPoint = 0.5 assert called - assert receivedValue == 0 - called = False - - uut.previousStoredAbLimits() - assert not called - - uut.nextStoredAbLimits() - assert called - assert receivedValue == 1 - called = False - - uut.nextStoredAbLimits() - assert not called - -def test_abLimitEnabledNotification(uut): + assert receivedValue == 0.5 called = False - receivedValue = None - def callback(value): - nonlocal called, receivedValue - called = True - receivedValue = value - uut.registerAbLimitEnabledCallback(callback) + # Adding list of key points does not trigger a notification + uut.keyPoints = [0.2, 0.4] assert not called - uut.setAbLimitEnable(False) + # Assigning the same key point again does not trigger a notification + uut.keyPoint = 0.5 assert not called - assert receivedValue is None - uut.setAbLimitEnable(True) - assert called - assert receivedValue == True - called = False - receivedValue = None - - uut.setAbLimitEnable(True) - assert not called - assert receivedValue is None - - uut.setAbLimitEnable(False) - assert called - assert receivedValue == False diff --git a/solo-tool-project/test/test_session.json b/solo-tool-project/test/test_session.json index f48b792..aed1e11 100644 --- a/solo-tool-project/test/test_session.json +++ b/solo-tool-project/test/test_session.json @@ -1,13 +1,10 @@ [ { "path" : "test.flac", - "ab_limits" : null + "key_positions" : null }, { "path" : "test.mp3", - "ab_limits" : [ - [0.1, 0.2], - [0.3, 0.4] - ] + "key_positions" : [0.1, 0.3] } ] -- cgit v1.2.3