package usecase import ( "context" "errors" "strings" "testing" "time" "github.com/gofrs/uuid/v5" "github.com/saveinmed/backend-go/internal/domain" ) type failingBatchRepo struct { *MockRepository } func (f *failingBatchRepo) BatchCreateProducts(ctx context.Context, products []domain.Product) error { return errors.New("boom") } func (f *failingBatchRepo) CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error { return errors.New("boom") } func TestImportProductsSuccess(t *testing.T) { repo := NewMockRepository() svc := NewService(repo, &MockPaymentGateway{}, &MockNotificationService{}, 2.5, "secret", time.Hour, "pepper") csvData := strings.NewReader("name,price,stock,description,ean\nAspirin,12.5,5,Anti-inflammatory,123\nIbuprofen,10,0,,\n") sellerID := uuid.Must(uuid.NewV7()) report, err := svc.ImportProducts(context.Background(), sellerID, csvData) if err != nil { t.Fatalf("unexpected error: %v", err) } if report.TotalProcessed != 2 { t.Fatalf("expected total processed 2, got %d", report.TotalProcessed) } if report.SuccessCount != 2 { t.Fatalf("expected success count 2, got %d", report.SuccessCount) } if report.FailedCount != 0 { t.Fatalf("expected failed count 0, got %d", report.FailedCount) } if len(repo.products) != 2 { t.Fatalf("expected 2 products, got %d", len(repo.products)) } if repo.products[0].SellerID != sellerID { t.Errorf("expected seller ID %s, got %s", sellerID, repo.products[0].SellerID) } if repo.products[0].PriceCents != 1250 { t.Errorf("expected price cents 1250, got %d", repo.products[0].PriceCents) } // Stock check removed (Dictionary Mode) } func TestImportProductsMissingHeaders(t *testing.T) { repo := NewMockRepository() svc := NewService(repo, &MockPaymentGateway{}, &MockNotificationService{}, 2.5, "secret", time.Hour, "pepper") csvData := strings.NewReader("ean,stock\n123,5\n") _, err := svc.ImportProducts(context.Background(), uuid.Must(uuid.NewV7()), csvData) if err == nil { t.Fatal("expected error for missing headers") } if !strings.Contains(err.Error(), "missing required header") { t.Fatalf("expected missing header error, got %v", err) } } func TestImportProductsEmptyCSV(t *testing.T) { repo := NewMockRepository() svc := NewService(repo, &MockPaymentGateway{}, &MockNotificationService{}, 2.5, "secret", time.Hour, "pepper") csvData := strings.NewReader("name,price\n") _, err := svc.ImportProducts(context.Background(), uuid.Must(uuid.NewV7()), csvData) if err == nil { t.Fatal("expected error for empty CSV") } if !strings.Contains(err.Error(), "csv file is empty") { t.Fatalf("expected empty csv error, got %v", err) } } func TestImportProductsInvalidRows(t *testing.T) { repo := NewMockRepository() svc := NewService(repo, &MockPaymentGateway{}, &MockNotificationService{}, 2.5, "secret", time.Hour, "pepper") csvData := strings.NewReader("name,price,stock\n,12.5,5\nValid,abc,2\nGood,5,1\n") sellerID := uuid.Must(uuid.NewV7()) report, err := svc.ImportProducts(context.Background(), sellerID, csvData) if err != nil { t.Fatalf("unexpected error: %v", err) } if report.TotalProcessed != 3 { t.Fatalf("expected total processed 3, got %d", report.TotalProcessed) } if report.FailedCount != 2 { t.Fatalf("expected failed count 2, got %d", report.FailedCount) } if report.SuccessCount != 1 { t.Fatalf("expected success count 1, got %d", report.SuccessCount) } if len(report.Errors) != 2 { t.Fatalf("expected 2 errors, got %d", len(report.Errors)) } if len(repo.products) != 1 { t.Fatalf("expected 1 product, got %d", len(repo.products)) } } func TestImportProductsBatchInsertFailure(t *testing.T) { baseRepo := NewMockRepository() repo := &failingBatchRepo{MockRepository: baseRepo} svc := NewService(repo, &MockPaymentGateway{}, &MockNotificationService{}, 2.5, "secret", time.Hour, "pepper") csvData := strings.NewReader("name,price\nItem,12.5\n") _, err := svc.ImportProducts(context.Background(), uuid.Must(uuid.NewV7()), csvData) if err == nil { t.Fatal("expected batch insert error") } if !strings.Contains(err.Error(), "batch insert failed") { t.Fatalf("expected batch insert error, got %v", err) } }