diff options
Diffstat (limited to 'solo-tool-project/test')
| -rw-r--r-- | solo-tool-project/test/abcontroller_unittest.py | 272 | ||||
| -rw-r--r-- | solo-tool-project/test/midi_launchpad_mini_integrationtest.py | 120 | ||||
| -rw-r--r-- | solo-tool-project/test/notifier_unittest.py | 3 | ||||
| -rw-r--r-- | solo-tool-project/test/session_manager_unittest.py | 137 | ||||
| -rw-r--r-- | solo-tool-project/test/solo_tool_controller_integrationtest.py | 2 | ||||
| -rw-r--r-- | solo-tool-project/test/solo_tool_integrationtest.py | 469 | ||||
| -rw-r--r-- | solo-tool-project/test/test_session.json | 7 | 
7 files changed, 229 insertions, 781 deletions
| 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]      }  ] | 
