You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Music/MusicTests/SmartPlaylistTests.swift

125 lines
5.3 KiB

import Foundation
import Testing
@testable import Music
struct SmartPlaylistTests {
// Creates a SmartPlaylist in memory and verifies its properties.
@Test func smartPlaylistProperties() throws {
let sp = SmartPlaylist(
id: nil,
name: "Miles Davis",
searchQuery: "miles davis",
createdAt: Date(),
conditions: nil
)
#expect(sp.name == "Miles Davis")
#expect(sp.searchQuery == "miles davis")
#expect(sp.isSmartPlaylist == true)
}
// Creates a smart playlist in the database and fetches it back.
@Test func createAndFetchSmartPlaylist() throws {
let db = try DatabaseService(inMemory: true)
let sp = try db.createSmartPlaylist(name: "Jazz Vibes", searchQuery: "jazz")
#expect(sp.id != nil)
#expect(sp.name == "Jazz Vibes")
#expect(sp.searchQuery == "jazz")
let all = try db.fetchSmartPlaylists()
#expect(all.count == 1)
#expect(all[0].name == "Jazz Vibes")
}
// Renames a smart playlist and verifies the new name persists.
@Test func renameSmartPlaylist() throws {
let db = try DatabaseService(inMemory: true)
let sp = try db.createSmartPlaylist(name: "Old Name", searchQuery: "old")
try db.renameSmartPlaylist(id: sp.id!, name: "New Name")
let all = try db.fetchSmartPlaylists()
#expect(all[0].name == "New Name")
}
// Updates the search query of a smart playlist.
@Test func updateSmartPlaylistQuery() throws {
let db = try DatabaseService(inMemory: true)
let sp = try db.createSmartPlaylist(name: "Jazz", searchQuery: "jazz")
try db.updateSmartPlaylistQuery(id: sp.id!, searchQuery: "jazz fusion")
let all = try db.fetchSmartPlaylists()
#expect(all[0].searchQuery == "jazz fusion")
}
// Deletes a smart playlist and verifies it's gone.
@Test func deleteSmartPlaylist() throws {
let db = try DatabaseService(inMemory: true)
let sp = try db.createSmartPlaylist(name: "To Delete", searchQuery: "delete")
try db.deleteSmartPlaylist(id: sp.id!)
let all = try db.fetchSmartPlaylists()
#expect(all.isEmpty)
}
// Verifies smart playlist tracks are computed via FTS5 search (not stored).
@Test func smartPlaylistReturnsDynamicResults() throws {
let db = try DatabaseService(inMemory: true)
var t1 = Track.fixture(fileURL: "/a.mp3", title: "Kind of Blue", artist: "Miles Davis")
var t2 = Track.fixture(fileURL: "/b.mp3", title: "Hotel California", artist: "Eagles")
var t3 = Track.fixture(fileURL: "/c.mp3", title: "Bitches Brew", artist: "Miles Davis")
try db.insert(&t1)
try db.insert(&t2)
try db.insert(&t3)
// Smart playlist uses the existing fetchTracks with its searchQuery
let results = try db.fetchTracks(search: "miles davis", sortColumn: "title", ascending: true)
#expect(results.count == 2)
#expect(results[0].title == "Bitches Brew")
#expect(results[1].title == "Kind of Blue")
}
// Creates a SmartPlaylist fixture with conditions and verifies the conditions
// field is preserved and the isSmartPlaylist flag is true.
@Test func smartPlaylistWithConditions() throws {
let conditions = [SmartPlaylistCondition(field: .artist, op: .equals, value: .string("Miles Davis"))]
let sp = SmartPlaylist.fixture(conditions: conditions)
#expect(sp.conditions?.count == 1)
#expect(sp.conditions?[0].field == .artist)
#expect(sp.isSmartPlaylist == true)
}
// Encodes and decodes a SmartPlaylistCondition to/from JSON,
// verifying that all fields survive the round-trip.
@Test func conditionCodableRoundTrip() throws {
let condition = SmartPlaylistCondition(
field: .artist,
op: .equals,
value: .string("Miles Davis")
)
let data = try JSONEncoder().encode(condition)
let decoded = try JSONDecoder().decode(SmartPlaylistCondition.self, from: data)
#expect(decoded.field == .artist)
#expect(decoded.op == .equals)
if case .string(let s) = decoded.value {
#expect(s == "Miles Davis")
} else {
Issue.record("Expected string value")
}
}
// Encodes and decodes an array of conditions with mixed value types.
@Test func conditionsArrayCodableRoundTrip() throws {
let conditions: [SmartPlaylistCondition] = [
SmartPlaylistCondition(field: .artist, op: .startsWith, value: .string("Miles")),
SmartPlaylistCondition(field: .year, op: .greaterThan, value: .int(1960)),
SmartPlaylistCondition(field: .dateAdded, op: .lessThan, value: .date(Date(timeIntervalSince1970: 0)))
]
let data = try JSONEncoder().encode(conditions)
let decoded = try JSONDecoder().decode([SmartPlaylistCondition].self, from: data)
#expect(decoded.count == 3)
#expect(decoded[0].field == .artist)
#expect(decoded[1].op == .greaterThan)
if case .int(let y) = decoded[1].value { #expect(y == 1960) } else { Issue.record("Expected int") }
if case .date(let d) = decoded[2].value { #expect(d == Date(timeIntervalSince1970: 0)) } else { Issue.record("Expected date") }
}
}