From 557b89ba0993d27fb119c79c6dcffd6101b79860 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Sun, 13 Feb 2022 22:47:25 +0000 Subject: [PATCH] Refactoring and tests for models complete (for now) --- app/models.py | 42 ++++---- app/musicmuster.py | 4 +- app/songdb.py | 2 +- test_models.py | 237 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 258 insertions(+), 27 deletions(-) diff --git a/app/models.py b/app/models.py index a897958..0f89c0c 100644 --- a/app/models.py +++ b/app/models.py @@ -249,14 +249,7 @@ class Playlists(Base): """ if not row: - last_row = session.query( - func.max(PlaylistTracks.row) - ).filter_by(playlist_id=self.id).first() - # if there are no rows, the above returns (None, ) which is True - if last_row and last_row[0]: - row = last_row[0] + 1 - else: - row = 0 + row = PlaylistTracks.next_free_row(session, self) PlaylistTracks(session, self.id, track.id, row) @@ -351,11 +344,19 @@ class PlaylistTracks(Base): session.commit() @staticmethod - def get_track_playlists(session, track_id): - """Return all PlaylistTracks objects with this track_id""" + def next_free_row(session, playlist): + """Return next free row number""" - return session.query(PlaylistTracks).filter( - PlaylistTracks.track_id == track_id).all() + last_row = session.query( + func.max(PlaylistTracks.row) + ).filter_by(playlist_id=playlist.id).first() + # if there are no rows, the above returns (None, ) which is True + if last_row and last_row[0] is not None: + row = last_row[0] + 1 + else: + row = 0 + + return row class Settings(Base): @@ -458,11 +459,6 @@ class Tracks(Base): except (NoResultFound, MultipleResultsFound): return None - @classmethod - def get_from_id(cls, session, id): - return session.query(Tracks).filter( - Tracks.id == id).one() - @classmethod def get_from_path(cls, session, path): """ @@ -501,17 +497,17 @@ class Tracks(Base): def search_artists(cls, session, text): return ( - session.query(Tracks) - .filter(Tracks.artist.ilike(f"%{text}%")) - .order_by(Tracks.title) + session.query(cls) + .filter(cls.artist.ilike(f"%{text}%")) + .order_by(cls.title) ).all() @classmethod def search_titles(cls, session, text): return ( - session.query(Tracks) - .filter(Tracks.title.ilike(f"%{text}%")) - .order_by(Tracks.title) + session.query(cls) + .filter(cls.title.ilike(f"%{text}%")) + .order_by(cls.title) ).all() def update_lastplayed(self, session): diff --git a/app/musicmuster.py b/app/musicmuster.py index f122344..5e256bc 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -447,7 +447,7 @@ class Window(QMainWindow, Ui_MainWindow): self.visible_playlist_tab().get_selected_rows_and_tracks() ): rows.append(row) - track = Tracks.get_from_id(session, track_id) + track = Tracks.get_by_id(session, track_id) if destination_visible_playlist_tab: # Insert with repaint=False to not update database destination_visible_playlist_tab.insert_track( @@ -883,7 +883,7 @@ class DbDialog(QDialog): self.select_searchtext() def add_track(self, track_id): - track = Tracks.get_from_id(self.session, track_id) + track = Tracks.get_by_id(self.session, track_id) # Add to playlist on screen # If we don't specify "repaint=False", playlist will # also be saved to database diff --git a/app/songdb.py b/app/songdb.py index 6758940..6173eb8 100755 --- a/app/songdb.py +++ b/app/songdb.py @@ -359,7 +359,7 @@ def update_db(session): f"File removed: {track.title=}, {track.artist=}, " f"{track.path=}" ) - for pt in PlaylistTracks.get_track_playlists(session, track.id): + for pt in [a.playlist.name for a in track.playlists] # Create note Notes.add_note(session, pt.playlist_id, pt.row, note_txt) # TODO: this needs to call playlist.add_note() now diff --git a/test_models.py b/test_models.py index 8a60e5d..8eec95b 100644 --- a/test_models.py +++ b/test_models.py @@ -1,3 +1,4 @@ +import os.path import time from app.models import ( @@ -173,6 +174,240 @@ def test_playlist_add_track(session): playlist.add_track(session, track) assert len(playlist.tracks) == 1 - print(playlist.tracks) playlist_track = playlist.tracks[0] assert playlist_track.path == track_path + + +def test_playlist_open_and_close(session): + + # We need a playlist + playlist = Playlists(session, "my playlist") + + assert len(Playlists.get_open(session)) == 1 + assert len(Playlists.get_closed(session)) == 0 + + playlist.close(session) + + assert len(Playlists.get_open(session)) == 0 + assert len(Playlists.get_closed(session)) == 1 + + playlist.mark_open(session) + + assert len(Playlists.get_open(session)) == 1 + assert len(Playlists.get_closed(session)) == 0 + + +def test_playlist_get_all_and_by_id(session): + # We need two playlists + p1_name = "playlist one" + p2_name = "playlist two" + playlist1 = Playlists(session, p1_name) + _ = Playlists(session, p2_name) + + all_playlists = Playlists.get_all(session) + assert len(all_playlists) == 2 + assert p1_name in [p.name for p in all_playlists] + assert p2_name in [p.name for p in all_playlists] + assert Playlists.get_by_id(session, playlist1.id).name == p1_name + + +def test_playlist_remove_tracks(session): + # Need two playlists and three tracks + p1_name = "playlist one" + playlist1 = Playlists(session, p1_name) + p2_name = "playlist two" + playlist2 = Playlists(session, p2_name) + + track1_path = "/a/b/c" + track1 = Tracks(session, track1_path) + track2_path = "/m/n/o" + track2 = Tracks(session, track2_path) + track3_path = "/x/y/z" + track3 = Tracks(session, track3_path) + + # Add all tracks to both playlists + for p in [playlist1, playlist2]: + for t in [track1, track2, track3]: + p.add_track(session, t) + + assert len(playlist1.tracks) == 3 + assert len(playlist2.tracks) == 3 + + playlist1.remove_track(session, 1) + assert len(playlist1.tracks) == 2 + + playlist1.remove_all_tracks(session) + assert len(playlist1.tracks) == 0 + assert len(playlist2.tracks) == 3 + + +def test_playlist_get_track_playlists(session): + # Need two playlists and two tracks + p1_name = "playlist one" + playlist1 = Playlists(session, p1_name) + p2_name = "playlist two" + playlist2 = Playlists(session, p2_name) + + track1_path = "/a/b/c" + track1 = Tracks(session, track1_path) + track2_path = "/m/n/o" + track2 = Tracks(session, track2_path) + + # Put track1 in both playlists, track2 only in playlist1 + playlist1.add_track(session, track1) + playlist2.add_track(session, track1) + playlist1.add_track(session, track2) + + playlists_track1 = track1.playlists + playlists_track2 = track2.playlists + assert p1_name in [a.playlist.name for a in playlists_track1] + assert p2_name in [a.playlist.name for a in playlists_track1] + assert p1_name in [a.playlist.name for a in playlists_track2] + assert p2_name not in [a.playlist.name for a in playlists_track2] + + +def test_tracks_get_all_paths(session): + # Need two tracks + track1_path = "/a/b/c" + track1 = Tracks(session, track1_path) + track2_path = "/m/n/o" + track2 = Tracks(session, track2_path) + + result = Tracks.get_all_paths(session) + assert track1_path in result + assert track2_path in result + + +def test_tracks_get_all_tracks(session): + # Need two tracks + track1_path = "/a/b/c" + track1 = Tracks(session, track1_path) + track2_path = "/m/n/o" + track2 = Tracks(session, track2_path) + + result = Tracks.get_all_tracks(session) + assert track1_path in [a.path for a in result] + assert track2_path in [a.path for a in result] + + +def test_tracks_get_or_create(session): + track1_path = "/a/b/c" + + track1 = Tracks.get_or_create(session, track1_path) + assert track1.path == track1_path + track2 = Tracks.get_or_create(session, track1_path) + assert track1 is track2 + + +def test_tracks_from_filename(session): + track1_path = "/a/b/c" + + track1 = Tracks(session, track1_path) + assert Tracks.get_from_filename( + session, os.path.basename(track1_path) + ) is track1 + + +def test_tracks_from_path(session): + track1_path = "/a/b/c" + + track1 = Tracks(session, track1_path) + assert Tracks.get_from_path(session, track1_path) is track1 + + +def test_tracks_by_id(session): + track1_path = "/a/b/c" + + track1 = Tracks(session, track1_path) + assert Tracks.get_by_id(session, track1.id) is track1 + + +def test_tracks_remove_by_path(session): + track1_path = "/a/b/c" + + track1 = Tracks(session, track1_path) + assert len(Tracks.get_all_tracks(session)) == 1 + Tracks.remove_by_path(session, track1_path) + assert len(Tracks.get_all_tracks(session)) == 0 + + +def test_tracks_search_artists(session): + + track1_path = "/a/b/c" + track1_artist = "Artist One" + track1 = Tracks(session, track1_path) + track1.artist = track1_artist + + track2_path = "/m/n/o" + track2_artist = "Artist Two" + track2 = Tracks(session, track2_path) + track2.artist = track2_artist + + session.commit() + + x = Tracks.get_all_tracks(session) + artist_first_word = track1_artist.split()[0].lower() + assert len(Tracks.search_artists(session, artist_first_word)) == 2 + assert len(Tracks.search_artists(session, track1_artist)) == 1 + + +def test_tracks_search_titles(session): + track1_path = "/a/b/c" + track1_title = "Title One" + track1 = Tracks(session, track1_path) + track1.title = track1_title + + track2_path = "/m/n/o" + track2_title = "Title Two" + track2 = Tracks(session, track2_path) + track2.title = track2_title + + session.commit() + + x = Tracks.get_all_tracks(session) + title_first_word = track1_title.split()[0].lower() + assert len(Tracks.search_titles(session, title_first_word)) == 2 + assert len(Tracks.search_titles(session, track1_title)) == 1 + + +def test_tracks_update_lastplayed(session): + track1_path = "/a/b/c" + track1 = Tracks(session, track1_path) + + assert track1.lastplayed is None + track1.update_lastplayed(session) + assert track1.lastplayed is not None + + +def test_tracks_update_info(session): + path = "/a/b/c" + artist = "The Beatles" + title = "Help!" + newinfo = "abcdef" + + track1 = Tracks(session, path) + track1.artist = artist + track1.title = title + + test1 = Tracks.get_by_id(session, track1.id) + assert test1.artist == artist + assert test1.title == title + assert test1.path == path + + track1.path = newinfo + test2 = Tracks.get_by_id(session, track1.id) + assert test2.artist == artist + assert test2.title == title + assert test2.path == newinfo + + track1.artist = newinfo + test2 = Tracks.get_by_id(session, track1.id) + assert test2.artist == newinfo + assert test2.title == title + assert test2.path == newinfo + + track1.title = newinfo + test3 = Tracks.get_by_id(session, track1.id) + assert test3.artist == newinfo + assert test3.title == newinfo + assert test3.path == newinfo