package handler import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "github.com/go-chi/chi/v5" "github.com/johnzastrow/actalog/pkg/middleware" ) // Test helper functions for handler tests // createTestRequest creates an HTTP request with optional body func createTestRequest(method, path, body string) *http.Request { req := httptest.NewRequest(method, path, strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") return req } // createAuthenticatedRequest creates a request with user context func createAuthenticatedRequest(method, path, body string, userID int64, email, role string) *http.Request { req := createTestRequest(method, path, body) ctx := context.WithValue(req.Context(), middleware.UserIDKey, userID) ctx = context.WithValue(ctx, middleware.UserEmailKey, email) ctx = context.WithValue(ctx, middleware.UserRoleKey, role) return req.WithContext(ctx) } // parseJSONResponse parses a JSON response body into the target func parseJSONResponse(rr *httptest.ResponseRecorder, target interface{}) error { return json.Unmarshal(rr.Body.Bytes(), target) } // assertStatusCode checks if response has expected status code func assertStatusCode(t interface{ Errorf(string, ...interface{}) }, rr *httptest.ResponseRecorder, expected int) { if rr.Code != expected { t.Errorf("handler returned wrong status code: got %v want %v, body: %s", rr.Code, expected, rr.Body.String()) } } // assertContentType checks if response has expected content type func assertContentType(t interface{ Errorf(string, ...interface{}) }, rr *httptest.ResponseRecorder, expected string) { ct := rr.Header().Get("Content-Type") if ct != expected { t.Errorf("handler returned wrong content type: got %v want %v", ct, expected) } } // assertBodyContains checks if response body contains expected string func assertBodyContains(t interface{ Errorf(string, ...interface{}) }, rr *httptest.ResponseRecorder, expected string) { if !strings.Contains(rr.Body.String(), expected) { t.Errorf("handler body does not contain %q: got %s", expected, rr.Body.String()) } } // addChiURLParam adds a chi URL parameter to a request context func addChiURLParam(r *http.Request, key, value string) *http.Request { rctx := chi.NewRouteContext() rctx.URLParams.Add(key, value) return r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx)) } // addChiURLParams adds multiple chi URL parameters to a request context func addChiURLParams(r *http.Request, params map[string]string) *http.Request { rctx := chi.NewRouteContext() for key, value := range params { rctx.URLParams.Add(key, value) } return r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx)) } // createUserIDOnlyRequest creates a request with only userID in context (no email or role) // Useful for testing "missing role" authorization checks func createUserIDOnlyRequest(method, path, body string, userID int64) *http.Request { req := createTestRequest(method, path, body) ctx := context.WithValue(req.Context(), middleware.UserIDKey, userID) return req.WithContext(ctx) } // createMultipartRequest creates a multipart form request for file upload testing // Returns nil if there's an error creating the request func createMultipartRequest(method, path, fieldName, fileName, contentType string, fileContent []byte, userID int64, email, role string) *http.Request { body := &strings.Builder{} // Create a simple multipart form body manually boundary := "----WebKitFormBoundary7MA4YWxkTrZu0gW" body.WriteString("--" + boundary + "\r\n") body.WriteString("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"\r\n") body.WriteString("Content-Type: " + contentType + "\r\n\r\n") body.WriteString(string(fileContent)) body.WriteString("\r\n--" + boundary + "--\r\n") req := httptest.NewRequest(method, path, strings.NewReader(body.String())) req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary) ctx := context.WithValue(req.Context(), middleware.UserIDKey, userID) ctx = context.WithValue(ctx, middleware.UserEmailKey, email) ctx = context.WithValue(ctx, middleware.UserRoleKey, role) return req.WithContext(ctx) }