|
|
|
|
@ -98,4 +98,133 @@ struct DatabaseServiceTests { |
|
|
|
|
let result = try db.fetchTracks(search: "", sortColumn: "DROP TABLE tracks", ascending: true) |
|
|
|
|
#expect(result[0].title == "Alpha") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Creates a playlist and verifies it can be fetched back. |
|
|
|
|
@Test func createAndFetchPlaylist() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
let playlist = try db.createPlaylist(name: "Chill Vibes") |
|
|
|
|
|
|
|
|
|
#expect(playlist.id != nil) |
|
|
|
|
#expect(playlist.name == "Chill Vibes") |
|
|
|
|
|
|
|
|
|
let all = try db.fetchPlaylists() |
|
|
|
|
#expect(all.count == 1) |
|
|
|
|
#expect(all[0].name == "Chill Vibes") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Renames a playlist and verifies the new name persists. |
|
|
|
|
@Test func renamePlaylist() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
let playlist = try db.createPlaylist(name: "Old Name") |
|
|
|
|
try db.renamePlaylist(id: playlist.id!, name: "New Name") |
|
|
|
|
|
|
|
|
|
let all = try db.fetchPlaylists() |
|
|
|
|
#expect(all[0].name == "New Name") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Deletes a playlist and verifies it's gone. |
|
|
|
|
@Test func deletePlaylist() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
let playlist = try db.createPlaylist(name: "To Delete") |
|
|
|
|
try db.deletePlaylist(id: playlist.id!) |
|
|
|
|
|
|
|
|
|
let all = try db.fetchPlaylists() |
|
|
|
|
#expect(all.isEmpty) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Adds tracks to a playlist and verifies order is preserved. |
|
|
|
|
@Test func addTracksToPlaylist() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
var t1 = Track.fixture(fileURL: "/a.mp3", title: "Song A") |
|
|
|
|
var t2 = Track.fixture(fileURL: "/b.mp3", title: "Song B") |
|
|
|
|
try db.insert(&t1) |
|
|
|
|
try db.insert(&t2) |
|
|
|
|
let playlist = try db.createPlaylist(name: "My Playlist") |
|
|
|
|
|
|
|
|
|
try db.addTrackToPlaylist(trackId: t1.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: t2.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
let tracks = try db.fetchPlaylistTracks(playlistId: playlist.id!) |
|
|
|
|
#expect(tracks.count == 2) |
|
|
|
|
#expect(tracks[0].title == "Song A") |
|
|
|
|
#expect(tracks[1].title == "Song B") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Removes a track from a playlist and verifies positions are compacted. |
|
|
|
|
@Test func removeTrackFromPlaylist() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
var t1 = Track.fixture(fileURL: "/a.mp3", title: "Song A") |
|
|
|
|
var t2 = Track.fixture(fileURL: "/b.mp3", title: "Song B") |
|
|
|
|
var t3 = Track.fixture(fileURL: "/c.mp3", title: "Song C") |
|
|
|
|
try db.insert(&t1) |
|
|
|
|
try db.insert(&t2) |
|
|
|
|
try db.insert(&t3) |
|
|
|
|
let playlist = try db.createPlaylist(name: "My Playlist") |
|
|
|
|
|
|
|
|
|
try db.addTrackToPlaylist(trackId: t1.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: t2.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: t3.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
// Remove middle track |
|
|
|
|
try db.removeTrackFromPlaylist(trackId: t2.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
let tracks = try db.fetchPlaylistTracks(playlistId: playlist.id!) |
|
|
|
|
#expect(tracks.count == 2) |
|
|
|
|
#expect(tracks[0].title == "Song A") |
|
|
|
|
#expect(tracks[1].title == "Song C") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Reorders tracks in a playlist (move last to first). |
|
|
|
|
@Test func reorderPlaylistTracks() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
var t1 = Track.fixture(fileURL: "/a.mp3", title: "Song A") |
|
|
|
|
var t2 = Track.fixture(fileURL: "/b.mp3", title: "Song B") |
|
|
|
|
var t3 = Track.fixture(fileURL: "/c.mp3", title: "Song C") |
|
|
|
|
try db.insert(&t1) |
|
|
|
|
try db.insert(&t2) |
|
|
|
|
try db.insert(&t3) |
|
|
|
|
let playlist = try db.createPlaylist(name: "My Playlist") |
|
|
|
|
|
|
|
|
|
try db.addTrackToPlaylist(trackId: t1.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: t2.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: t3.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
// Move Song C (position 2) to position 0 |
|
|
|
|
try db.reorderPlaylistTrack(playlistId: playlist.id!, fromPosition: 2, toPosition: 0) |
|
|
|
|
|
|
|
|
|
let tracks = try db.fetchPlaylistTracks(playlistId: playlist.id!) |
|
|
|
|
#expect(tracks[0].title == "Song C") |
|
|
|
|
#expect(tracks[1].title == "Song A") |
|
|
|
|
#expect(tracks[2].title == "Song B") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Verifies that deleting a playlist cascades to playlist_tracks. |
|
|
|
|
@Test func deletePlaylistCascadesJoinRows() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
var track = Track.fixture() |
|
|
|
|
try db.insert(&track) |
|
|
|
|
let playlist = try db.createPlaylist(name: "Temp") |
|
|
|
|
try db.addTrackToPlaylist(trackId: track.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
try db.deletePlaylist(id: playlist.id!) |
|
|
|
|
|
|
|
|
|
// Re-create a playlist to verify no orphan join rows cause issues |
|
|
|
|
let playlist2 = try db.createPlaylist(name: "Temp2") |
|
|
|
|
let tracks = try db.fetchPlaylistTracks(playlistId: playlist2.id!) |
|
|
|
|
#expect(tracks.isEmpty) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Verifies adding a duplicate track to a playlist is silently ignored. |
|
|
|
|
@Test func addDuplicateTrackToPlaylistIsIgnored() throws { |
|
|
|
|
let db = try DatabaseService(inMemory: true) |
|
|
|
|
var track = Track.fixture() |
|
|
|
|
try db.insert(&track) |
|
|
|
|
let playlist = try db.createPlaylist(name: "My Playlist") |
|
|
|
|
|
|
|
|
|
try db.addTrackToPlaylist(trackId: track.id!, playlistId: playlist.id!) |
|
|
|
|
try db.addTrackToPlaylist(trackId: track.id!, playlistId: playlist.id!) |
|
|
|
|
|
|
|
|
|
let tracks = try db.fetchPlaylistTracks(playlistId: playlist.id!) |
|
|
|
|
#expect(tracks.count == 1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|