package service import ( "context" "errors" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" ) func newMockGormDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) { t.Helper() sqlDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) } gdb, err := gorm.Open(mysql.New(mysql.Config{ Conn: sqlDB, SkipInitializeWithVersion: true, }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) if err != nil { _ = sqlDB.Close() t.Fatalf("gorm.Open: %v", err) } cleanup := func() { _ = sqlDB.Close() } return gdb, mock, cleanup } func TestHasActiveMembership(t *testing.T) { t.Parallel() now := time.Date(2026, 2, 28, 16, 0, 0, 0, time.Local) db, mock, cleanup := newMockGormDB(t) defer cleanup() mock.ExpectQuery("SELECT count\\(\\*\\) FROM `user_memberships`"). WithArgs(uint(100), uint(200), "active", now). WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) ok, err := hasActiveMembership(context.Background(), db, 100, 200, now) if err != nil { t.Fatalf("hasActiveMembership: %v", err) } if !ok { t.Fatalf("hasActiveMembership got=false, want=true") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet expectations: %v", err) } } func TestHasActiveMembershipNotFound(t *testing.T) { t.Parallel() now := time.Date(2026, 2, 28, 16, 0, 0, 0, time.Local) db, mock, cleanup := newMockGormDB(t) defer cleanup() mock.ExpectQuery("SELECT count\\(\\*\\) FROM `user_memberships`"). WithArgs(uint(101), uint(201), "active", now). WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) ok, err := hasActiveMembership(context.Background(), db, 101, 201, now) if err != nil { t.Fatalf("hasActiveMembership: %v", err) } if ok { t.Fatalf("hasActiveMembership got=true, want=false") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet expectations: %v", err) } } func TestHasActiveMembershipDBError(t *testing.T) { t.Parallel() now := time.Date(2026, 2, 28, 16, 0, 0, 0, time.Local) db, mock, cleanup := newMockGormDB(t) defer cleanup() mock.ExpectQuery("SELECT count\\(\\*\\) FROM `user_memberships`"). WithArgs(uint(102), uint(202), "active", now). WillReturnError(errors.New("db unavailable")) _, err := hasActiveMembership(context.Background(), db, 102, 202, now) if err == nil { t.Fatalf("expected error when query fails") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet expectations: %v", err) } }