package postgres import ( "context" "regexp" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/gofrs/uuid/v5" "github.com/jmoiron/sqlx" "github.com/saveinmed/backend-go/internal/domain" "github.com/stretchr/testify/assert" ) func newMockRepo(t *testing.T) (*Repository, sqlmock.Sqlmock) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } sqlxDB := sqlx.NewDb(db, "sqlmock") repo := New(sqlxDB) return repo, mock } func TestCreateCompany(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() company := &domain.Company{ ID: uuid.Must(uuid.NewV7()), CNPJ: "12345678901234", CorporateName: "Test Pharmacy", Category: "farmacia", LicenseNumber: "123", IsVerified: false, Latitude: -10.0, Longitude: -20.0, City: "Test City", State: "TS", Phone: "(11) 99999-9999", OperatingHours: "08:00-18:00", Is24Hours: false, CreatedAt: time.Now(), UpdatedAt: time.Now(), } query := `INSERT INTO companies` mock.ExpectExec(regexp.QuoteMeta(query)). WithArgs( company.ID, company.CNPJ, company.CorporateName, company.Category, company.LicenseNumber, company.IsVerified, company.Latitude, company.Longitude, company.City, company.State, company.Phone, company.OperatingHours, company.Is24Hours, sqlmock.AnyArg(), sqlmock.AnyArg(), ). WillReturnResult(sqlmock.NewResult(1, 1)) err := repo.CreateCompany(context.Background(), company) assert.NoError(t, err) if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } } func TestGetCompany(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() id := uuid.Must(uuid.NewV7()) rows := sqlmock.NewRows([]string{"id", "cnpj", "corporate_name", "category", "license_number", "is_verified", "latitude", "longitude", "city", "state", "created_at", "updated_at"}). AddRow(id, "123", "Test", "farmacia", "123", false, 0.0, 0.0, "City", "ST", time.Now(), time.Now()) mock.ExpectQuery(`SELECT .* FROM companies WHERE id = \$1`). WithArgs(id). WillReturnRows(rows) company, err := repo.GetCompany(context.Background(), id) assert.NoError(t, err) if company != nil { assert.Equal(t, id, company.ID) } else { t.Error("expected company to not be nil") } } func TestCreateProduct(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() product := &domain.Product{ ID: uuid.Must(uuid.NewV7()), SellerID: uuid.Must(uuid.NewV7()), EANCode: "7891234567890", Name: "Test Product", Description: "Desc", Manufacturer: "Test Manufacturer", Category: "medicamento", Subcategory: "analgesico", PriceCents: 1000, Observations: "Test observations", InternalCode: "INT-001", FactoryPriceCents: 800, PMCCents: 1100, CommercialDiscountCents: 50, TaxSubstitutionCents: 25, InvoicePriceCents: 900, } query := `INSERT INTO products` rows := sqlmock.NewRows([]string{"created_at", "updated_at"}). AddRow(time.Now(), time.Now()) mock.ExpectQuery(regexp.QuoteMeta(query)). WithArgs( product.ID, product.SellerID, product.EANCode, product.Name, product.Description, product.Manufacturer, product.Category, product.Subcategory, product.PriceCents, product.Observations, product.InternalCode, product.FactoryPriceCents, product.PMCCents, product.CommercialDiscountCents, product.TaxSubstitutionCents, product.InvoicePriceCents, ). WillReturnRows(rows) err := repo.CreateProduct(context.Background(), product) assert.NoError(t, err) } func TestListProducts(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() rows := sqlmock.NewRows([]string{"id", "seller_id", "ean_code", "name", "description", "manufacturer", "category", "subcategory", "price_cents", "observations", "created_at", "updated_at"}). AddRow(uuid.Must(uuid.NewV7()), uuid.Must(uuid.NewV7()), "789", "P1", "Desc", "Lab", "cat", "sub", 1000, "obs", time.Now(), time.Now()) mock.ExpectQuery(`SELECT count\(\*\) FROM products`).WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) mock.ExpectQuery(`SELECT .* FROM products`).WithArgs(10, 0).WillReturnRows(rows) list, count, err := repo.ListProducts(context.Background(), domain.ProductFilter{Limit: 10}) assert.NoError(t, err) assert.Equal(t, int64(1), count) assert.Len(t, list, 1) } func TestCreateUser(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() user := &domain.User{ ID: uuid.Must(uuid.NewV7()), CompanyID: uuid.Must(uuid.NewV7()), Role: domain.RoleEmployee, Name: "Test User", Username: "testuser", Email: "test@example.com", PasswordHash: "hashed_password", } query := `INSERT INTO users` mock.ExpectExec(regexp.QuoteMeta(query)). WithArgs( user.ID, user.CompanyID, user.Role, user.Name, user.Username, user.Email, user.EmailVerified, user.PasswordHash, user.Superadmin, user.NomeSocial, user.CPF, sqlmock.AnyArg(), sqlmock.AnyArg(), ). WillReturnResult(sqlmock.NewResult(1, 1)) err := repo.CreateUser(context.Background(), user) assert.NoError(t, err) } func TestListUsers(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() companyID := uuid.Must(uuid.NewV7()) userID := uuid.Must(uuid.NewV7()) rows := sqlmock.NewRows([]string{ "id", "company_id", "role", "name", "username", "email", "email_verified", "password_hash", "created_at", "updated_at", }).AddRow( userID, companyID, domain.RoleOwner, "Test", "test", "test@test.com", true, "hash", time.Now(), time.Now(), ) mock.ExpectQuery(`SELECT count\(\*\) FROM users`). WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) mock.ExpectQuery(`SELECT .* FROM users`). WithArgs(20, 0). WillReturnRows(rows) mock.ExpectQuery(`SELECT \* FROM addresses WHERE entity_id = ANY`). WillReturnRows(sqlmock.NewRows([]string{"id", "entity_id", "title", "zip_code", "street", "number", "complement", "district", "city", "state", "latitude", "longitude", "created_at", "updated_at"})) mock.ExpectQuery(`SELECT \* FROM companies WHERE id = ANY`). WillReturnRows(sqlmock.NewRows([]string{"id", "cnpj", "corporate_name", "category", "license_number", "is_verified", "latitude", "longitude", "city", "state", "phone", "operating_hours", "is_24_hours", "created_at", "updated_at"}). AddRow(companyID, "123", "Company", "farmacia", "123", true, 0.0, 0.0, "City", "ST", "", "", false, time.Now(), time.Now())) list, count, err := repo.ListUsers(context.Background(), domain.UserFilter{Limit: 20}) assert.NoError(t, err) assert.Equal(t, int64(1), count) assert.Len(t, list, 1) } func TestListOrders(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() orderID := uuid.Must(uuid.NewV7()) buyerID := uuid.Must(uuid.NewV7()) sellerID := uuid.Must(uuid.NewV7()) rows := sqlmock.NewRows([]string{ "id", "buyer_id", "seller_id", "status", "total_cents", "payment_method", "shipping_recipient_name", "shipping_street", "shipping_number", "shipping_complement", "shipping_district", "shipping_city", "shipping_state", "shipping_zip_code", "shipping_country", "created_at", "updated_at", }).AddRow( orderID, buyerID, sellerID, "Pendente", 10000, "pix", "Test User", "Test Street", "123", "", "Centro", "City", "ST", "12345-678", "Brasil", time.Now(), time.Now(), ) mock.ExpectQuery(`SELECT count\(\*\) FROM orders`). WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) mock.ExpectQuery(`SELECT .* FROM orders`). WithArgs(20, 0). WillReturnRows(rows) mock.ExpectQuery(`SELECT .* FROM order_items WHERE order_id`). WithArgs(orderID). WillReturnRows(sqlmock.NewRows([]string{"id", "order_id", "product_id", "quantity", "unit_cents", "batch", "expires_at"})) list, count, err := repo.ListOrders(context.Background(), domain.OrderFilter{Limit: 20}) assert.NoError(t, err) assert.Equal(t, int64(1), count) assert.Len(t, list, 1) } func TestGetShippingSettings(t *testing.T) { repo, mock := newMockRepo(t) defer repo.db.Close() vendorID := uuid.Must(uuid.NewV7()) rows := sqlmock.NewRows([]string{ "vendor_id", "active", "max_radius_km", "price_per_km_cents", "min_fee_cents", "free_shipping_threshold_cents", "pickup_active", "pickup_address", "pickup_hours", "latitude", "longitude", "created_at", "updated_at", }).AddRow( vendorID, true, 50.0, 150, 1000, nil, true, "Rua Test, 123", "08:00-18:00", -23.55, -46.63, time.Now(), time.Now(), ) mock.ExpectQuery(`SELECT \* FROM shipping_settings WHERE vendor_id`). WithArgs(vendorID). WillReturnRows(rows) settings, err := repo.GetShippingSettings(context.Background(), vendorID) assert.NoError(t, err) assert.NotNil(t, settings) assert.Equal(t, vendorID, settings.VendorID) assert.True(t, settings.Active) }