package kway import ( "testing" "time" ) // TestPlayRecord is a simple implementation of Mergeable for testing type TestPlayRecord struct { TrackName string Artist string time time.Time Source string // "lastfm" or "spotify" HasMBID bool } func (r TestPlayRecord) IsDuplicate(other TestPlayRecord, tolerance time.Duration) (bool, bool) { return r.SameAs(other, tolerance), r.BetterThan(other) } func (r TestPlayRecord) SameAs(other TestPlayRecord, tolerance time.Duration) bool { if r.TrackName != other.TrackName { return false } if r.Artist != other.Artist { return false } diff := r.time.Sub(other.time) if diff < 0 { diff = -diff } return diff <= tolerance } func (r TestPlayRecord) BetterThan(other TestPlayRecord) bool { if r.Source == "lastfm" && other.Source != "lastfm" { return true } if r.Source != "lastfm" && other.Source == "lastfm" { return false } return r.HasMBID && !other.HasMBID } func (r TestPlayRecord) Time() time.Time { return r.time } func TestMerge(t *testing.T) { baseTime := time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC) // Test case where duplicates are very close in time and should be merged lastfmRecords := []TestPlayRecord{ {TrackName: "Song A", Artist: "Artist", time: baseTime, Source: "lastfm"}, {TrackName: "Song D", Artist: "Artist", time: baseTime.Add(3 * time.Hour), Source: "lastfm"}, } spotifyRecords := []TestPlayRecord{ {TrackName: "Song A", Artist: "Artist", time: baseTime.Add(3 * time.Minute), Source: "spotify"}, // Duplicate within tolerance {TrackName: "Song B", Artist: "Artist", time: baseTime.Add(time.Hour), Source: "spotify"}, {TrackName: "Song C", Artist: "Artist", time: baseTime.Add(2 * time.Hour), Source: "spotify"}, } result := Merge([][]TestPlayRecord{lastfmRecords, spotifyRecords}, 10*time.Minute) if len(result) != 4 { t.Errorf("Expected 4 results, got %d", len(result)) } // Check order - should be sorted by time expectedOrder := []string{"Song A", "Song B", "Song C", "Song D"} for i, expected := range expectedOrder { if i >= len(result) { t.Errorf("Missing result at position %d", i) break } if result[i].TrackName != expected { t.Errorf("Result %d should be %s, got %s", i, expected, result[i].TrackName) } } // Check that LastFM version is preferred for duplicate Song A if result[0].Source != "lastfm" { t.Errorf("Duplicate Song A should be from lastfm, got %s", result[0].Source) } } func TestMergeExactDuplicate(t *testing.T) { baseTime := time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC) lastfmRecords := []TestPlayRecord{ {TrackName: "Song A", Artist: "Artist", time: baseTime, Source: "lastfm"}, } spotifyRecords := []TestPlayRecord{ {TrackName: "Song A", Artist: "Artist", time: baseTime, Source: "spotify"}, // Exact duplicate } result := Merge([][]TestPlayRecord{lastfmRecords, spotifyRecords}, 0) if len(result) != 1 { t.Errorf("Expected 1 result, got %d", len(result)) } // Check that LastFM version is preferred if result[0].Source != "lastfm" { t.Errorf("Duplicate should be from lastfm, got %s", result[0].Source) } } func TestMergeEmptySources(t *testing.T) { result := Merge([][]TestPlayRecord{}, 0) if len(result) != 0 { t.Errorf("Expected empty result, got %d items", len(result)) } result = Merge([][]TestPlayRecord{{}, {}}, 0) if len(result) != 0 { t.Errorf("Expected empty result from empty sources, got %d items", len(result)) } }