package subscription import ( "testing" "time" "github.com/google/uuid" ) func TestPlanTableName(t *testing.T) { p := Plan{} if p.TableName() != "subscription_plans" { t.Errorf("expected subscription_plans, got %s", p.TableName()) } } func TestUserSubscriptionTableName(t *testing.T) { s := UserSubscription{} if s.TableName() != "user_subscriptions" { t.Errorf("expected user_subscriptions, got %s", s.TableName()) } } func TestInvoiceTableName(t *testing.T) { i := Invoice{} if i.TableName() != "subscription_invoices" { t.Errorf("expected subscription_invoices, got %s", i.TableName()) } } func TestPlanConstants(t *testing.T) { tests := []struct { name string plan PlanName expected string }{ {"free plan", PlanFree, "free"}, {"creator plan", PlanCreator, "creator"}, {"premium plan", PlanPremium, "premium"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if string(tt.plan) != tt.expected { t.Errorf("expected %s, got %s", tt.expected, string(tt.plan)) } }) } } func TestSubscriptionStatusConstants(t *testing.T) { tests := []struct { name string status SubscriptionStatus expected string }{ {"active", StatusActive, "active"}, {"trialing", StatusTrialing, "trialing"}, {"canceled", StatusCanceled, "canceled"}, {"past_due", StatusPastDue, "past_due"}, {"expired", StatusExpired, "expired"}, } 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 TestBillingCycleConstants(t *testing.T) { if string(BillingMonthly) != "monthly" { t.Errorf("expected monthly, got %s", string(BillingMonthly)) } if string(BillingYearly) != "yearly" { t.Errorf("expected yearly, got %s", string(BillingYearly)) } } func TestInvoiceStatusConstants(t *testing.T) { tests := []struct { name string status InvoiceStatus expected string }{ {"pending", InvoicePending, "pending"}, {"paid", InvoicePaid, "paid"}, {"failed", InvoiceFailed, "failed"}, {"refunded", InvoiceRefunded, "refunded"}, } 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 TestUserSubscription_IsTrialing(t *testing.T) { tests := []struct { name string sub UserSubscription expected bool }{ { name: "trialing with future trial end", sub: UserSubscription{ Status: StatusTrialing, TrialEnd: timePtr(time.Now().Add(24 * time.Hour)), }, expected: true, }, { name: "trialing with past trial end", sub: UserSubscription{ Status: StatusTrialing, TrialEnd: timePtr(time.Now().Add(-24 * time.Hour)), }, expected: false, }, { name: "active status", sub: UserSubscription{ Status: StatusActive, }, expected: false, }, { name: "trialing without trial end", sub: UserSubscription{ Status: StatusTrialing, }, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.sub.IsTrialing(); got != tt.expected { t.Errorf("IsTrialing() = %v, want %v", got, tt.expected) } }) } } func TestUserSubscription_IsActiveOrTrialing(t *testing.T) { tests := []struct { name string status SubscriptionStatus expected bool }{ {"active", StatusActive, true}, {"trialing", StatusTrialing, true}, {"canceled", StatusCanceled, false}, {"expired", StatusExpired, false}, {"past_due", StatusPastDue, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sub := UserSubscription{Status: tt.status} if got := sub.IsActiveOrTrialing(); got != tt.expected { t.Errorf("IsActiveOrTrialing() = %v, want %v", got, tt.expected) } }) } } func TestPlanFields(t *testing.T) { plan := Plan{ ID: uuid.New(), Name: PlanPremium, DisplayName: "Premium", PriceMonthly: 1999, PriceYearly: 19999, Currency: "USD", StorageLimitBytes: 214748364800, MarketplaceCommission: 0.10, CanSellOnMarketplace: true, HasPrioritySupport: true, HasCollaborationTools: true, HasDistribution: true, TrialDays: 14, IsActive: true, SortOrder: 2, } if plan.PriceMonthly != 1999 { t.Errorf("expected price_monthly_cents 1999, got %d", plan.PriceMonthly) } if plan.PriceYearly != 19999 { t.Errorf("expected price_yearly_cents 19999, got %d", plan.PriceYearly) } if plan.TrialDays != 14 { t.Errorf("expected trial_days 14, got %d", plan.TrialDays) } if plan.MarketplaceCommission != 0.10 { t.Errorf("expected commission 0.10, got %f", plan.MarketplaceCommission) } } func TestServiceErrors(t *testing.T) { if ErrPlanNotFound.Error() != "subscription plan not found" { t.Errorf("unexpected error message: %s", ErrPlanNotFound.Error()) } if ErrAlreadySubscribed.Error() != "user already has an active subscription to this plan" { t.Errorf("unexpected error message: %s", ErrAlreadySubscribed.Error()) } if ErrNoActiveSubscription.Error() != "no active subscription found" { t.Errorf("unexpected error message: %s", ErrNoActiveSubscription.Error()) } if ErrInvalidBillingCycle.Error() != "invalid billing cycle: must be 'monthly' or 'yearly'" { t.Errorf("unexpected error message: %s", ErrInvalidBillingCycle.Error()) } if ErrFreePlanNoBilling.Error() != "free plan does not require billing" { t.Errorf("unexpected error message: %s", ErrFreePlanNoBilling.Error()) } } func timePtr(t time.Time) *time.Time { return &t }