import Foundation import Testing import GRDB @testable import Music struct TrackTests { // Creates a fresh in-memory database with the tracks table schema. // Each test gets its own isolated DatabaseQueue so tests don't share state. private static func makeDB() throws -> DatabaseQueue { let dbQueue = try DatabaseQueue() try dbQueue.write { db in try db.create(table: "tracks") { t in t.autoIncrementedPrimaryKey("id") t.column("fileURL", .text).notNull().unique() t.column("title", .text).notNull() t.column("artist", .text).notNull() t.column("albumArtist", .text).notNull() t.column("album", .text).notNull() t.column("genre", .text).notNull() t.column("year", .integer) t.column("trackNumber", .integer) t.column("discNumber", .integer) t.column("duration", .double).notNull() t.column("bpm", .integer) t.column("composer", .text).notNull() t.column("fileFormat", .text).notNull() t.column("bitrate", .integer) t.column("sampleRate", .integer) t.column("fileSize", .integer).notNull() t.column("playCount", .integer).notNull().defaults(to: 0) t.column("lastPlayedAt", .datetime) t.column("rating", .integer).notNull().defaults(to: 0) t.column("dateAdded", .datetime).notNull() t.column("dateModified", .datetime).notNull() t.column("fileHash", .text).notNull() } } return dbQueue } // Verifies that Track can round-trip through GRDB's encoding/decoding, // meaning it correctly conforms to FetchableRecord and PersistableRecord. @Test func roundTripThroughDatabase() throws { let dbQueue = try TrackTests.makeDB() try dbQueue.write { db in var track = Track.fixture(title: "Bohemian Rhapsody", artist: "Queen") try track.insert(db) #expect(track.id != nil) let fetched = try Track.fetchOne(db, key: track.id) #expect(fetched?.title == "Bohemian Rhapsody") #expect(fetched?.artist == "Queen") #expect(fetched?.duration == 210.0) } } // Verifies that didInsert assigns the auto-incremented ID after insertion. @Test func didInsertAssignsId() throws { let dbQueue = try TrackTests.makeDB() try dbQueue.write { db in var track = Track.fixture() #expect(track.id == nil) try track.insert(db) #expect(track.id != nil) } } // Verifies the fileHash computation produces a deterministic string from size + date. @Test func computeHashIsDeterministic() { let date = Date(timeIntervalSince1970: 1700000000) let hash1 = Track.computeHash(fileSize: 5_000_000, modificationDate: date) let hash2 = Track.computeHash(fileSize: 5_000_000, modificationDate: date) #expect(hash1 == hash2) #expect(hash1 == "5000000_1700000000") let different = Track.computeHash(fileSize: 999, modificationDate: date) #expect(different != hash1) } }