package distribution import ( "encoding/json" "testing" "time" "github.com/google/uuid" ) func TestTrackDistributionTableName(t *testing.T) { d := TrackDistribution{} if d.TableName() != "track_distributions" { t.Errorf("expected track_distributions, got %s", d.TableName()) } } func TestStatusHistoryEntryTableName(t *testing.T) { e := StatusHistoryEntry{} if e.TableName() != "track_distribution_status_history" { t.Errorf("expected track_distribution_status_history, got %s", e.TableName()) } } func TestExternalStreamingRoyaltyTableName(t *testing.T) { r := ExternalStreamingRoyalty{} if r.TableName() != "external_streaming_royalties" { t.Errorf("expected external_streaming_royalties, got %s", r.TableName()) } } func TestDistributionStatusConstants(t *testing.T) { tests := []struct { name string status DistributionStatus expected string }{ {"submitted", StatusSubmitted, "submitted"}, {"processing", StatusProcessing, "processing"}, {"live", StatusLive, "live"}, {"rejected", StatusRejected, "rejected"}, {"removed", StatusRemoved, "removed"}, {"failed", StatusFailed, "failed"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if string(tt.status) != tt.expected { t.Errorf("expected %s, got %s", tt.expected, string(tt.status)) } }) } } func TestPlatformConstants(t *testing.T) { tests := []struct { name string platform Platform expected string }{ {"spotify", PlatformSpotify, "spotify"}, {"apple_music", PlatformAppleMusic, "apple_music"}, {"deezer", PlatformDeezer, "deezer"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if string(tt.platform) != tt.expected { t.Errorf("expected %s, got %s", tt.expected, string(tt.platform)) } }) } } func TestAllPlatforms(t *testing.T) { platforms := AllPlatforms() if len(platforms) != 3 { t.Errorf("expected 3 platforms, got %d", len(platforms)) } expected := map[Platform]bool{ PlatformSpotify: true, PlatformAppleMusic: true, PlatformDeezer: true, } for _, p := range platforms { if !expected[p] { t.Errorf("unexpected platform: %s", p) } } } func TestImportStatusConstants(t *testing.T) { tests := []struct { name string status ImportStatus expected string }{ {"pending", ImportPending, "pending"}, {"completed", ImportCompleted, "completed"}, {"failed", ImportFailed, "failed"}, {"partial", ImportPartial, "partial"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if string(tt.status) != tt.expected { t.Errorf("expected %s, got %s", tt.expected, string(tt.status)) } }) } } func TestTrackDistribution_PlatformStatuses(t *testing.T) { dist := &TrackDistribution{} statuses := map[Platform]PlatformStatus{ PlatformSpotify: {Status: "live", URL: "https://open.spotify.com/track/123"}, PlatformDeezer: {Status: "processing"}, } if err := dist.SetPlatformStatuses(statuses); err != nil { t.Fatalf("SetPlatformStatuses failed: %v", err) } got, err := dist.GetPlatformStatuses() if err != nil { t.Fatalf("GetPlatformStatuses failed: %v", err) } if got[PlatformSpotify].Status != "live" { t.Errorf("expected spotify status live, got %s", got[PlatformSpotify].Status) } if got[PlatformSpotify].URL != "https://open.spotify.com/track/123" { t.Errorf("unexpected spotify URL: %s", got[PlatformSpotify].URL) } if got[PlatformDeezer].Status != "processing" { t.Errorf("expected deezer status processing, got %s", got[PlatformDeezer].Status) } } func TestTrackDistribution_GetMetadata(t *testing.T) { meta := DistributionMetadata{ ArtistName: "Test Artist", AlbumName: "Single", Genre: "Electronic", ReleaseDate: "2026-03-10", TrackTitle: "Test Track", } metaJSON, _ := json.Marshal(meta) dist := &TrackDistribution{ Metadata: metaJSON, } got, err := dist.GetMetadata() if err != nil { t.Fatalf("GetMetadata failed: %v", err) } if got.ArtistName != "Test Artist" { t.Errorf("expected Test Artist, got %s", got.ArtistName) } if got.Genre != "Electronic" { t.Errorf("expected Electronic, got %s", got.Genre) } } func TestServiceErrors(t *testing.T) { tests := []struct { name string err error msg string }{ {"distribution not found", ErrDistributionNotFound, "distribution not found"}, {"not eligible", ErrNotEligible, "distribution requires Creator or Premium plan"}, {"track not public", ErrTrackNotPublic, "track must be public to distribute"}, {"already distributed", ErrAlreadyDistributed, "track already has a pending or live distribution"}, {"no platforms", ErrNoPlatformsSelected, "at least one platform must be selected"}, {"not removable", ErrDistributionNotRemovable, "distribution cannot be removed in current status"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.err.Error() != tt.msg { t.Errorf("expected %q, got %q", tt.msg, tt.err.Error()) } }) } } func TestExternalStreamingRoyaltyFields(t *testing.T) { now := time.Now() r := ExternalStreamingRoyalty{ ID: uuid.New(), TrackID: uuid.New(), CreatorID: uuid.New(), ReportingPeriodStart: now, ReportingPeriodEnd: now.AddDate(0, 1, 0), Platform: string(PlatformSpotify), TotalStreams: 50000, TotalRevenueCents: 17500, Currency: "USD", Distributor: "distrokid", ImportStatus: ImportCompleted, } if r.TotalStreams != 50000 { t.Errorf("expected 50000 streams, got %d", r.TotalStreams) } if r.TotalRevenueCents != 17500 { t.Errorf("expected 17500 cents, got %d", r.TotalRevenueCents) } if r.ImportStatus != ImportCompleted { t.Errorf("expected completed, got %s", r.ImportStatus) } } func TestRoyaltySummary(t *testing.T) { summary := RoyaltySummary{ TotalStreams: 150000, TotalRevenueCents: 52500, ByPlatform: map[string]PlatformRoyaltySummary{ "spotify": {Streams: 50000, RevenueCents: 17500}, "apple_music": {Streams: 60000, RevenueCents: 21000}, "deezer": {Streams: 40000, RevenueCents: 14000}, }, } if summary.TotalStreams != 150000 { t.Errorf("expected 150000, got %d", summary.TotalStreams) } if len(summary.ByPlatform) != 3 { t.Errorf("expected 3 platforms in summary, got %d", len(summary.ByPlatform)) } if summary.ByPlatform["spotify"].RevenueCents != 17500 { t.Errorf("expected spotify revenue 17500, got %d", summary.ByPlatform["spotify"].RevenueCents) } }