import Foundation import Testing @testable import Music // Verifies the pure single/multi-track edit logic: extraction, change detection, // shared-vs-mixed across many tracks, and applying only edited fields. struct EditableTrackFieldsTests { @Test func initCopiesEditableValues() { // Step 1: build fields from a fixture track. let t = Track.fixture(title: "A", artist: "B", album: "C", year: 2001, rating: 3) let f = EditableTrackFields(from: t) // Step 2: editable values match. #expect(f.title == "A"); #expect(f.artist == "B") #expect(f.album == "C"); #expect(f.year == 2001); #expect(f.rating == 3) } @Test func changedFieldsDetectsOnlyDifferences() { // Step 1: two field sets differing only in genre + bpm. let a = EditableTrackFields(from: .fixture(genre: "Rock", bpm: 120)) var b = a; b.genre = "Jazz"; b.bpm = 90 // Step 2: change set is exactly {genre, bpm}. #expect(a.changedFields(to: b) == [.genre, .bpm]) } @Test func sharedMarksDifferingFieldsMixed() { // Step 1: two tracks share artist but differ in genre. let t1 = Track.fixture(artist: "Same", genre: "Rock") let t2 = Track.fixture(artist: "Same", genre: "Pop") // Step 2: shared() returns common artist and flags genre as mixed. let (values, mixed) = EditableTrackFields.shared(across: [t1, t2]) #expect(values.artist == "Same") #expect(mixed.contains(.genre)) #expect(!mixed.contains(.artist)) } @Test func sharedAcrossThreeTracksAccumulatesMixed() { // Step 1: three tracks all share the same album, but title differs on the // third track and genre differs on the second — so both title and // genre must end up "mixed", while album stays shared. let t1 = Track.fixture(title: "Same", album: "One Album", genre: "Rock") let t2 = Track.fixture(title: "Same", album: "One Album", genre: "Pop") let t3 = Track.fixture(title: "Different", album: "One Album", genre: "Rock") // Step 2: shared() over all three. let (values, mixed) = EditableTrackFields.shared(across: [t1, t2, t3]) // Step 3: album is shared (not mixed); title + genre are mixed. #expect(values.album == "One Album") #expect(!mixed.contains(.album)) #expect(mixed.contains(.title)) #expect(mixed.contains(.genre)) } @Test func applyOnlyWritesEditedFields() { // Step 1: a track and a fields object that changes album only. let t = Track.fixture(album: "Old", genre: "Rock") var f = EditableTrackFields(from: t); f.album = "New"; f.genre = "IGNORED" // Step 2: applying with editing={.album} changes album, leaves genre. let out = f.apply(editing: [.album], to: t) #expect(out.album == "New") #expect(out.genre == "Rock") } @Test func applyEmptyEditSetReturnsUnchanged() { let t = Track.fixture(title: "Keep") let f = EditableTrackFields(from: t) #expect(f.apply(editing: [], to: t) == t) } }