# Standard library imports import os import unittest from typing import Optional # PyQt imports from PyQt6.QtCore import Qt, QModelIndex # Third party imports from sqlalchemy.orm.session import Session # App imports from app.log import log from app.helpers import get_file_metadata # Set up test database before importing db # Mark subsequent lines to ignore E402, imports not at top of file DB_FILE = "/tmp/mm.db" if os.path.exists(DB_FILE): os.unlink(DB_FILE) os.environ["ALCHEMICAL_DATABASE_URI"] = "sqlite:///" + DB_FILE from app import playlistmodel # noqa: E402 from app.models import ( # noqa: E402 db, Playlists, Settings, Tracks, ) # class TestMMMiscTracks(unittest.TestCase): # def setUp(self): # PLAYLIST_NAME = "tracks playlist" # self.test_tracks = [ # "testdata/isa.mp3", # "testdata/isa_with_gap.mp3", # "testdata/loser.mp3", # "testdata/lovecats-10seconds.mp3", # "testdata/lovecats.mp3", # "testdata/mom.mp3", # "testdata/sitting.mp3", # ] # db.create_all() # # Create a playlist and model # with db.Session() as session: # self.playlist = Playlists(session, PLAYLIST_NAME) # self.model = playlistmodel.PlaylistModel(self.playlist.id) # for row in range(len(self.test_tracks)): # track_path = self.test_tracks[row % len(self.test_tracks)] # metadata = get_file_metadata(track_path) # track = Tracks(session, **metadata) # self.model.insert_row( # proposed_row_number=row, track_id=track.id, note=f"{row=}" # ) # session.commit() # def tearDown(self): # db.drop_all() # def test_7_row_playlist(self): # # Test auto-created playlist # assert self.model.rowCount() == 7 # assert max(self.model.playlist_rows.keys()) == 6 # for row in range(self.model.rowCount()): # assert row in self.model.playlist_rows # assert self.model.playlist_rows[row].plr_rownum == row class TestMMMiscRowMove(unittest.TestCase): def setUp(self): PLAYLIST_NAME = "rowmove playlist" ROWS_TO_CREATE = 11 db.create_all() with db.Session() as session: self.playlist = Playlists(session, PLAYLIST_NAME) self.model = playlistmodel.PlaylistModel(self.playlist.id) for row in range(ROWS_TO_CREATE): print(f"{row=}") self.model.insert_row(proposed_row_number=row, note=str(row)) session.commit() def tearDown(self): db.drop_all() def test_move_rows_test2(self): # move row 3 to row 5 self.model.move_rows([3], 5) # Check we have all rows and plr_rownums are correct for row in range(self.model.rowCount()): assert row in self.model.playlist_rows assert self.model.playlist_rows[row].plr_rownum == row if row not in [3, 4, 5]: assert self.model.playlist_rows[row].note == str(row) elif row == 3: assert self.model.playlist_rows[row].note == str(4) elif row == 4: assert self.model.playlist_rows[row].note == str(5) elif row == 5: assert self.model.playlist_rows[row].note == str(3) # def test_move_rows_test3(monkeypatch, session): # # move row 4 to row 3 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([4], 3) # # Check we have all rows and plr_rownums are correct # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # if row not in [3, 4]: # assert model.playlist_rows[row].note == str(row) # elif row == 3: # assert model.playlist_rows[row].note == str(4) # elif row == 4: # assert model.playlist_rows[row].note == str(3) # def test_move_rows_test4(monkeypatch, session): # # move row 4 to row 2 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([4], 2) # # Check we have all rows and plr_rownums are correct # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # if row not in [2, 3, 4]: # assert model.playlist_rows[row].note == str(row) # elif row == 2: # assert model.playlist_rows[row].note == str(4) # elif row == 3: # assert model.playlist_rows[row].note == str(2) # elif row == 4: # assert model.playlist_rows[row].note == str(3) # def test_move_rows_test5(monkeypatch, session): # # move rows [1, 4, 5, 10] → 8 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([1, 4, 5, 10], 8) # # Check we have all rows and plr_rownums are correct # new_order = [] # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # new_order.append(int(model.playlist_rows[row].note)) # assert new_order == [0, 2, 3, 6, 7, 8, 9, 1, 4, 5, 10] # def test_move_rows_test6(monkeypatch, session): # # move rows [3, 6] → 5 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([3, 6], 5) # # Check we have all rows and plr_rownums are correct # new_order = [] # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # new_order.append(int(model.playlist_rows[row].note)) # assert new_order == [0, 1, 2, 4, 5, 3, 6, 7, 8, 9, 10] # def test_move_rows_test7(monkeypatch, session): # # move rows [3, 5, 6] → 8 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([3, 5, 6], 8) # # Check we have all rows and plr_rownums are correct # new_order = [] # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # new_order.append(int(model.playlist_rows[row].note)) # assert new_order == [0, 1, 2, 4, 7, 8, 9, 10, 3, 5, 6] # def test_move_rows_test8(monkeypatch, session): # # move rows [7, 8, 10] → 5 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_playlist_rows(session, 11) # model.move_rows([7, 8, 10], 5) # # Check we have all rows and plr_rownums are correct # new_order = [] # for row in range(model.rowCount()): # assert row in model.playlist_rows # assert model.playlist_rows[row].plr_rownum == row # new_order.append(int(model.playlist_rows[row].note)) # assert new_order == [0, 1, 2, 3, 4, 7, 8, 10, 5, 6, 9] # def test_insert_header_row_end(monkeypatch, session): # # insert header row at end of playlist # monkeypatch.setattr(playlistmodel, "Session", session) # note_text = "test text" # initial_row_count = 11 # model = create_model_with_playlist_rows(session, initial_row_count) # model.insert_row(proposed_row_number=None, note=note_text) # assert model.rowCount() == initial_row_count + 1 # prd = model.playlist_rows[model.rowCount() - 1] # # Test against edit_role because display_role for headers is # # handled differently (sets up row span) # assert ( # model.edit_role(model.rowCount() - 1, playlistmodel.Col.NOTE.value, prd) # == note_text # ) # def test_insert_header_row_middle(monkeypatch, session): # # insert header row in middle of playlist # monkeypatch.setattr(playlistmodel, "Session", session) # note_text = "test text" # initial_row_count = 11 # insert_row = 6 # model = create_model_with_playlist_rows(session, initial_row_count) # model.insert_row(proposed_row_number=insert_row, note=note_text) # assert model.rowCount() == initial_row_count + 1 # prd = model.playlist_rows[insert_row] # # Test against edit_role because display_role for headers is # # handled differently (sets up row span) # assert ( # model.edit_role(model.rowCount() - 1, playlistmodel.Col.NOTE.value, prd) # == note_text # ) # def test_add_track_to_header(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # note_text = "test text" # initial_row_count = 11 # insert_row = 6 # model = create_model_with_playlist_rows(session, initial_row_count) # model.insert_row(proposed_row_number=insert_row, note=note_text) # assert model.rowCount() == initial_row_count + 1 # prd = model.playlist_rows[1] # model.add_track_to_header(insert_row, prd.track_id) # def test_create_model_with_tracks(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_tracks(session) # assert len(model.playlist_rows) == len(self.test_tracks) # def test_timing_one_track(monkeypatch, session): # START_ROW = 0 # END_ROW = 2 # monkeypatch.setattr(playlistmodel, "Session", session) # model = create_model_with_tracks(session) # model.insert_row(proposed_row_number=START_ROW, note="start+") # model.insert_row(proposed_row_number=END_ROW, note="-") # prd = model.playlist_rows[START_ROW] # qv_value = model.display_role(START_ROW, playlistmodel.HEADER_NOTES_COLUMN, prd) # assert qv_value.value() == "start [1 tracks, 4:23 unplayed]" # def test_insert_track_new_playlist(monkeypatch, session): # # insert a track into a new playlist # monkeypatch.setattr(playlistmodel, "Session", session) # playlist = Playlists(session, "test playlist") # # Create a model # model = playlistmodel.PlaylistModel(playlist.id) # track_path = self.test_tracks[0] # metadata = get_file_metadata(track_path) # track = Tracks(session, **metadata) # model.insert_row(proposed_row_number=0, track_id=track.id) # prd = model.playlist_rows[model.rowCount() - 1] # assert ( # model.edit_role(model.rowCount() - 1, playlistmodel.Col.TITLE.value, prd) # == metadata["title"] # ) # def test_reverse_row_groups_one_row(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # rows_to_move = [3] # model_src = create_model_with_playlist_rows(session, 5, name="source") # result = model_src._reversed_contiguous_row_groups(rows_to_move) # assert len(result) == 1 # assert result[0] == [3] # def test_reverse_row_groups_multiple_row(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # rows_to_move = [2, 3, 4, 5, 7, 9, 10, 13, 17, 20, 21] # model_src = create_model_with_playlist_rows(session, 5, name="source") # result = model_src._reversed_contiguous_row_groups(rows_to_move) # assert result == [[20, 21], [17], [13], [9, 10], [7], [2, 3, 4, 5]] # def test_move_one_row_between_playlists_to_end(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # create_rowcount = 5 # from_rows = [3] # to_row = create_rowcount # model_src = create_model_with_playlist_rows(session, create_rowcount, name="source") # model_dst = create_model_with_playlist_rows( # session, create_rowcount, name="destination" # ) # model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id) # model_dst.refresh_data(session) # assert len(model_src.playlist_rows) == create_rowcount - len(from_rows) # assert len(model_dst.playlist_rows) == create_rowcount + len(from_rows) # assert sorted([a.plr_rownum for a in model_src.playlist_rows.values()]) == list( # range(len(model_src.playlist_rows)) # ) # def test_move_one_row_between_playlists_to_middle(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # create_rowcount = 5 # from_rows = [3] # to_row = 2 # model_src = create_model_with_playlist_rows(session, create_rowcount, name="source") # model_dst = create_model_with_playlist_rows( # session, create_rowcount, name="destination" # ) # model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id) # model_dst.refresh_data(session) # # Check the rows of the destination model # row_notes = [] # for row_number in range(model_dst.rowCount()): # index = model_dst.index( # row_number, playlistmodel.Col.TITLE.value, QModelIndex() # ) # row_notes.append(model_dst.data(index, Qt.ItemDataRole.EditRole).value()) # assert len(model_src.playlist_rows) == create_rowcount - len(from_rows) # assert len(model_dst.playlist_rows) == create_rowcount + len(from_rows) # assert [int(a) for a in row_notes] == [0, 1, 3, 2, 3, 4] # def test_move_multiple_rows_between_playlists_to_end(monkeypatch, session): # monkeypatch.setattr(playlistmodel, "Session", session) # create_rowcount = 5 # from_rows = [1, 3, 4] # to_row = 2 # model_src = create_model_with_playlist_rows(session, create_rowcount, name="source") # model_dst = create_model_with_playlist_rows( # session, create_rowcount, name="destination" # ) # model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id) # model_dst.refresh_data(session) # # Check the rows of the destination model # row_notes = [] # for row_number in range(model_dst.rowCount()): # index = model_dst.index( # row_number, playlistmodel.Col.TITLE.value, QModelIndex() # ) # row_notes.append(model_dst.data(index, Qt.ItemDataRole.EditRole).value()) # assert len(model_src.playlist_rows) == create_rowcount - len(from_rows) # assert len(model_dst.playlist_rows) == create_rowcount + len(from_rows) # assert [int(a) for a in row_notes] == [0, 1, 3, 4, 1, 2, 3, 4] # # def test_edit_header(monkeypatch, session): # edit header row in middle of playlist # # monkeypatch.setattr(playlistmodel, "Session", session) # # note_text = "test text" # # initial_row_count = 11 # # insert_row = 6 # # model = create_model_with_playlist_rows(session, initial_row_count) # # model.insert_header_row(insert_row, note_text) # # assert model.rowCount() == initial_row_count + 1 # # prd = model.playlist_rows[insert_row] # # # Test against edit_role because display_role for headers is # # # handled differently (sets up row span) # # assert ( # # model.edit_role(model.rowCount(), playlistmodel.Col.NOTE.value, prd) # # == note_text # # )