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", "TEST-ACCESS-TOKEN", "http://localhost:8214", 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", "TEST-ACCESS-TOKEN", "http://localhost:8214", 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() // ctx is already declared above payer := &domain.User{Email: "buyer@test.com", Name: "Buyer", CPF: "12345678901"} pref, err := gateway.CreatePreference(ctx, order, payer, nil) 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", "TEST-ACCESS-TOKEN", "http://localhost:8214", tc.commission) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: tc.totalCents, } payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} pref, err := gateway.CreatePreference(context.Background(), order, payer, nil) 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", "TEST-ACCESS-TOKEN", "http://localhost:8214", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } ctx, cancel := context.WithCancel(context.Background()) cancel() // Cancel immediately payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} _, err := gateway.CreatePreference(ctx, order, payer, nil) if err == nil { t.Error("expected error for cancelled context") } } func TestCreatePreferenceWithTimeout(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", "TEST-ACCESS-TOKEN", "http://localhost:8214", 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) payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} _, err := gateway.CreatePreference(ctx, order, payer, nil) if err == nil { t.Error("expected error for timed out context") } } func TestCreatePreferenceWithZeroTotal(t *testing.T) { gateway := NewMercadoPagoGateway("https://api.mercadopago.com", "TEST-ACCESS-TOKEN", "http://localhost:8214", 2.5) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 0, } payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} pref, err := gateway.CreatePreference(context.Background(), order, payer, nil) 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) } } // Asaas Gateway Tests func TestNewAsaasGateway(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) if gateway.APIKey != "aact_test" { t.Errorf("expected APIKey 'aact_test', got '%s'", gateway.APIKey) } if gateway.WalletID != "wallet123" { t.Errorf("expected WalletID 'wallet123', got '%s'", gateway.WalletID) } if gateway.Environment != "sandbox" { t.Errorf("expected Environment 'sandbox', got '%s'", gateway.Environment) } if gateway.MarketplaceCommission != 12.0 { t.Errorf("expected commission 12.0, got %f", gateway.MarketplaceCommission) } } func TestAsaasBaseURL_Sandbox(t *testing.T) { gateway := NewAsaasGateway("key", "wallet", "sandbox", 12.0) expected := "https://sandbox.asaas.com/api/v3" if gateway.BaseURL() != expected { t.Errorf("expected %s, got %s", expected, gateway.BaseURL()) } } func TestAsaasBaseURL_Production(t *testing.T) { gateway := NewAsaasGateway("key", "wallet", "production", 12.0) expected := "https://api.asaas.com/v3" if gateway.BaseURL() != expected { t.Errorf("expected %s, got %s", expected, gateway.BaseURL()) } } func TestAsaasCreatePreference(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } ctx := context.Background() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} pref, err := gateway.CreatePreference(ctx, order, payer, nil) if err != nil { t.Fatalf("failed to create preference: %v", err) } if pref.Gateway != "asaas" { t.Errorf("expected gateway 'asaas', got '%s'", pref.Gateway) } if pref.MarketplaceFee != 1200 { t.Errorf("expected fee 1200, got %d", pref.MarketplaceFee) } if pref.SellerReceivable != 8800 { t.Errorf("expected seller receivable 8800, got %d", pref.SellerReceivable) } } func TestAsaasCreatePixPayment(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx := context.Background() pix, err := gateway.CreatePixPayment(ctx, order) if err != nil { t.Fatalf("failed to create pix payment: %v", err) } if pix.Gateway != "asaas" { t.Errorf("expected gateway 'asaas', got '%s'", pix.Gateway) } if pix.Status != "pending" { t.Errorf("expected status 'pending', got '%s'", pix.Status) } if pix.AmountCents != 5000 { t.Errorf("expected amount 5000, got %d", pix.AmountCents) } if pix.MarketplaceFee != 600 { t.Errorf("expected fee 600, got %d", pix.MarketplaceFee) } if pix.QRCode == "" { t.Error("expected QRCode to be set") } } func TestAsaasCreateBoletoPayment(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 10000, } customer := &domain.Customer{ ID: uuid.Must(uuid.NewV7()), Name: "Test Customer", Email: "test@test.com", } ctx := context.Background() boleto, err := gateway.CreateBoletoPayment(ctx, order, customer) if err != nil { t.Fatalf("failed to create boleto payment: %v", err) } if boleto.Gateway != "asaas" { t.Errorf("expected gateway 'asaas', got '%s'", boleto.Gateway) } if boleto.Status != "pending" { t.Errorf("expected status 'pending', got '%s'", boleto.Status) } if boleto.AmountCents != 10000 { t.Errorf("expected amount 10000, got %d", boleto.AmountCents) } if boleto.BarCode == "" { t.Error("expected BarCode to be set") } } func TestAsaasConfirmPayment(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) ctx := context.Background() result, err := gateway.ConfirmPayment(ctx, "pay_123") if err != nil { t.Fatalf("failed to confirm payment: %v", err) } if result.Status != "confirmed" { t.Errorf("expected status 'confirmed', got '%s'", result.Status) } if result.Gateway != "asaas" { t.Errorf("expected gateway 'asaas', got '%s'", result.Gateway) } } func TestAsaasRefundPayment(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) ctx := context.Background() result, err := gateway.RefundPayment(ctx, "pay_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 TestAsaasCreateSubaccount(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) seller := &domain.Company{ ID: uuid.Must(uuid.NewV7()), CorporateName: "Test Seller", CNPJ: "12345678000199", } ctx := context.Background() account, err := gateway.CreateSubaccount(ctx, seller) if err != nil { t.Fatalf("failed to create subaccount: %v", err) } if account.Gateway != "asaas" { t.Errorf("expected gateway 'asaas', got '%s'", account.Gateway) } if account.Status != "active" { t.Errorf("expected status 'active', got '%s'", account.Status) } if account.AccountType != "subaccount" { t.Errorf("expected type 'subaccount', got '%s'", account.AccountType) } } func TestAsaasContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx, cancel := context.WithCancel(context.Background()) cancel() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} _, err := gateway.CreatePreference(ctx, order, payer, nil) if err == nil { t.Error("expected error for cancelled context") } } func TestAsaasPixContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.CreatePixPayment(ctx, order) if err == nil { t.Error("expected error for cancelled context") } } func TestAsaasBoletoContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) order := &domain.Order{ ID: uuid.Must(uuid.NewV7()), TotalCents: 5000, } customer := &domain.Customer{ID: uuid.Must(uuid.NewV7())} ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.CreateBoletoPayment(ctx, order, customer) if err == nil { t.Error("expected error for cancelled context") } } func TestAsaasConfirmContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.ConfirmPayment(ctx, "pay_123") if err == nil { t.Error("expected error for cancelled context") } } func TestAsaasRefundContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.RefundPayment(ctx, "pay_123", 5000) if err == nil { t.Error("expected error for cancelled context") } } func TestAsaasSubaccountContextCancellation(t *testing.T) { gateway := NewAsaasGateway("aact_test", "wallet123", "sandbox", 12.0) seller := &domain.Company{ID: uuid.Must(uuid.NewV7())} ctx, cancel := context.WithCancel(context.Background()) cancel() _, err := gateway.CreateSubaccount(ctx, seller) if err == nil { t.Error("expected error for cancelled context") } } // 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() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} pref, err := gateway.CreatePreference(ctx, order, payer, nil) 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() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} pref, err := gateway.CreatePreference(ctx, order, payer, nil) 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() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} _, err := gateway.CreatePreference(ctx, order, payer, nil) 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() payer := &domain.User{Email: "buyer@test.com", Name: "Buyer"} _, err := gateway.CreatePreference(ctx, order, payer, nil) if err == nil { t.Error("expected error for cancelled context") } }