package controllers import ( "fmt" "net/http" "net/http/httptest" "testing" "GoMembership/internal/constants" "GoMembership/internal/models" "GoMembership/pkg/logger" "github.com/gin-gonic/gin" ) type RegisterSubscriptionTest struct { WantDBData map[string]interface{} Input string Name string WantResponse int Assert bool } type MockUserController struct { UserController // Embed the UserController } func (m *MockUserController) ExtractUserFromContext(c *gin.Context) (*models.User, error) { return &models.User{ ID: 1, FirstName: "Admin", LastName: "User", Email: "admin@test.com", RoleID: constants.Roles.Admin, }, nil } func setupMockAuth() { // Create and assign the mock controller mockController := &MockUserController{} Mc.UserController = mockController } func testMembershipController(t *testing.T) { setupMockAuth() tests := getSubscriptionData() for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("MembershipController : %v", tt.Name) logger.Error.Print("==============================================================") t.Run(tt.Name, func(t *testing.T) { if err := runSingleTest(&tt); err != nil { t.Errorf("Test failed: %v", err.Error()) } }) } } func (rt *RegisterSubscriptionTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { return GetMockedJSONContext([]byte(rt.Input), "api/subscription") } func (rt *RegisterSubscriptionTest) RunHandler(c *gin.Context, router *gin.Engine) { Mc.RegisterSubscription(c) } func (rt *RegisterSubscriptionTest) ValidateResponse(w *httptest.ResponseRecorder) error { if w.Code != rt.WantResponse { return fmt.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, rt.WantResponse) } return nil } func (rt *RegisterSubscriptionTest) ValidateResult() error { return validateSubscription(rt.Assert, rt.WantDBData) } func validateSubscription(assert bool, wantDBData map[string]interface{}) error { subscriptions, err := Mc.Service.GetSubscriptions(wantDBData) if err != nil { return fmt.Errorf("Error in database ops: %#v", err) } if assert != (len(*subscriptions) != 0) { return fmt.Errorf("Subscription entry query didn't met expectation: %v != %#v", assert, *subscriptions) } return nil } func getBaseSubscription() MembershipData { return MembershipData{ // APIKey: config.Auth.APIKEY, Subscription: models.SubscriptionModel{ Name: "Premium", Details: "A subscription detail", MonthlyFee: 12.0, HourlyRate: 14.0, }, } } func customizeSubscription(customize func(MembershipData) MembershipData) MembershipData { subscription := getBaseSubscription() return customize(subscription) } func getSubscriptionData() []RegisterSubscriptionTest { return []RegisterSubscriptionTest{ { Name: "Missing details should fail", WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Just a Subscription"}, Assert: false, Input: GenerateInputJSON( customizeSubscription(func(subscription MembershipData) MembershipData { subscription.Subscription.Details = "" return subscription })), }, { Name: "Missing model name should fail", WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": ""}, Assert: false, Input: GenerateInputJSON( customizeSubscription(func(subscription MembershipData) MembershipData { subscription.Subscription.Name = "" return subscription })), }, { Name: "Negative monthly fee should fail", WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: false, Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData { sub.Subscription.MonthlyFee = -10.0 return sub })), }, { Name: "Negative hourly rate should fail", WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: false, Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData { sub.Subscription.HourlyRate = -1.0 return sub })), }, { Name: "correct entry should pass", WantResponse: http.StatusCreated, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: true, Input: GenerateInputJSON( customizeSubscription(func(subscription MembershipData) MembershipData { subscription.Subscription.Conditions = "Some Condition" subscription.Subscription.IncludedPerYear = 0 subscription.Subscription.IncludedPerMonth = 1 return subscription })), }, { Name: "Duplicate subscription name should fail", WantResponse: http.StatusConflict, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: true, // The original subscription should still exist Input: GenerateInputJSON(getBaseSubscription()), }, } }