package payments import ( "context" "testing" "time" "github.com/gofrs/uuid/v5" "github.com/saveinmed/backend-go/internal/domain" ) func TestNewMercadoPagoGateway(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5) if gateway.BaseURL != "https://api.mercadopago.com" { t.Errorf("expected BaseURL 'https://api.mercadopago.com', got '%s'", gateway.BaseURL) } if gateway.MarketplaceCommission != 2.5 { t.Errorf("expected commission 2.5, got %f", gateway.MarketplaceCommission) } } func TestCreatePreference(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), BuyerID: uuid.Must(uuid.NewV7()), SellerID: uuid.Must(uuid.NewV7()), TotalCents: 10000, // R$100 } ctx := context.Background() pref, err := gateway.CreatePreference(ctx, order) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.OrderID != order.ID { t.Errorf("expected order ID %s, got %s", order.ID, pref.OrderID) } if pref.Gateway != "mercadopago" { t.Errorf("expected gateway 'mercadopago', got '%s'", pref.Gateway) } if pref.CommissionPct != 2.5 { t.Errorf("expected commission 2.5, got %f", pref.CommissionPct) } // Test marketplace fee calculation (2.5% of 10000 = 250) expectedFee := int64(250) if pref.MarketplaceFee != expectedFee { t.Errorf("expected marketplace fee %d, got %d", expectedFee, pref.MarketplaceFee) } // Test seller receivable calculation (10000 - 250 = 9750) expectedReceivable := int64(9750) if pref.SellerReceivable != expectedReceivable { t.Errorf("expected seller receivable %d, got %d", expectedReceivable, pref.SellerReceivable) } // Test payment URL format expectedURL := "https://api.mercadopago.com/checkout/v1/redirect?order_id=" + order.ID.String() if pref.PaymentURL != expectedURL { t.Errorf("expected URL '%s', got '%s'", expectedURL, pref.PaymentURL) } } func TestCreatePreferenceWithDifferentCommissions(t *testing.T) { testCases := []struct { name string commission float64 totalCents int64 expectedFee int64 expectedSeller int64 }{ {"5% commission", 5.0, 10000, 500, 9500}, {"10% commission", 10.0, 10000, 1000, 9000}, {"0% commission", 0.0, 10000, 0, 10000}, {"2.5% on large order", 2.5, 100000, 2500, 97500}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { gateway := NewMercadoPagoGateway("https://test.com", tc.commission) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: tc.totalCents, } pref, err := gateway.CreatePreference(context.Background(), order) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.MarketplaceFee != tc.expectedFee { t.Errorf("expected fee %d, got %d", tc.expectedFee, pref.MarketplaceFee) } if pref.SellerReceivable != tc.expectedSeller { t.Errorf("expected seller receivable %d, got %d", tc.expectedSeller, pref.SellerReceivable) } }) } } func TestCreatePreferenceWithCancelledContext(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } ctx, cancel := context.WithCancel(context.Background()) cancel() // Cancel immediately _, err := gateway.CreatePreference(ctx, order) if err == nil { t.Error("expected error for cancelled context") } } func TestCreatePreferenceWithTimeout(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } // Create a context that will timeout after a very short duration ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) defer cancel() // Wait for context to expire time.Sleep(10 * time.Millisecond) _, err := gateway.CreatePreference(ctx, order) if err == nil { t.Error("expected error for timed out context") } } func TestCreatePreferenceWithZeroTotal(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 0, } pref, err := gateway.CreatePreference(context.Background(), order) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.MarketplaceFee != 0 { t.Errorf("expected fee 0, got %d", pref.MarketplaceFee) } if pref.SellerReceivable != 0 { t.Errorf("expected seller receivable 0, got %d", pref.SellerReceivable) } } // Stripe Gateway Tests func TestNewStripeGateway(t *testing.T) { gateway := NewStripeGateway("sk_test_xxx", 12.0) if gateway.APIKey != "sk_test_xxx" { t.Errorf("expected APIKey 'sk_test_xxx', got '%s'", gateway.APIKey) } if gateway.MarketplaceCommission != 12.0 { t.Errorf("expected commission 12.0, got %f", gateway.MarketplaceCommission) } } func TestStripeCreatePreference(t *testing.T) { gateway := NewStripeGateway("sk_test_xxx", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), BuyerID: uuid.Must(uuid.NewV7()), SellerID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } ctx := context.Background() pref, err := gateway.CreatePreference(ctx, order) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.Gateway != "stripe" { t.Errorf("expected gateway 'stripe', got '%s'", pref.Gateway) } if pref.MarketplaceFee != 1200 { // 12% t.Errorf("expected fee 1200, got %d", pref.MarketplaceFee) } if pref.SellerReceivable != 8800 { t.Errorf("expected seller receivable 8800, got %d", pref.SellerReceivable) } } func TestStripeCreatePaymentIntent(t *testing.T) { gateway := NewStripeGateway("sk_test_xxx", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), SellerID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } ctx := context.Background() intent, err := gateway.CreatePaymentIntent(ctx, order) if err != nil { t.Fatalf("failed to create payment intent: %v", err) } if intent["currency"] != "brl" { t.Errorf("expected currency 'brl', got %v", intent["currency"]) } if intent["amount"].(int64) != 10000 { t.Errorf("expected amount 10000, got %v", intent["amount"]) } if intent["application_fee"].(int64) != 1200 { t.Errorf("expected fee 1200, got %v", intent["application_fee"]) } } // Mock Gateway Tests func TestNewMockGateway(t *testing.T) { gateway := NewMockGateway(12.0, true) if gateway.MarketplaceCommission != 12.0 { t.Errorf("expected commission 12.0, got %f", gateway.MarketplaceCommission) } if !gateway.AutoApprove { t.Error("expected AutoApprove true") } } func TestMockCreatePreference(t *testing.T) { gateway := NewMockGateway(12.0, true) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx := context.Background() pref, err := gateway.CreatePreference(ctx, order) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.Gateway != "mock" { t.Errorf("expected gateway 'mock', got '%s'", pref.Gateway) } if pref.MarketplaceFee != 600 { t.Errorf("expected fee 600, got %d", pref.MarketplaceFee) } } func TestMockConfirmPayment(t *testing.T) { gateway := NewMockGateway(12.0, true) ctx := context.Background() result, err := gateway.ConfirmPayment(ctx, "mock-payment-123") if err != nil { t.Fatalf("failed to confirm payment: %v", err) } if result.Status != "approved" { t.Errorf("expected status 'approved', got '%s'", result.Status) } if result.Gateway != "mock" { t.Errorf("expected gateway 'mock', got '%s'", result.Gateway) } } func TestMockRefundPayment(t *testing.T) { gateway := NewMockGateway(12.0, true) ctx := context.Background() result, err := gateway.RefundPayment(ctx, "mock-payment-123", 5000) if err != nil { t.Fatalf("failed to refund payment: %v", err) } if result.Status != "refunded" { t.Errorf("expected status 'refunded', got '%s'", result.Status) } if result.AmountCents != 5000 { t.Errorf("expected amount 5000, got %d", result.AmountCents) } } func TestMockContextCancellation(t *testing.T) { gateway := NewMockGateway(12.0, true) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.CreatePreference(ctx, order) if err == nil { t.Error("expected error for cancelled context") } } func TestStripeContextCancellation(t *testing.T) { gateway := NewStripeGateway("sk_test_xxx", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.CreatePreference(ctx, order) if err == nil { t.Error("expected error for cancelled context") } }