package handlers import ( "bytes" "encoding/json" "mime/multipart" "net/http" "net/http/httptest" "testing" imageModels "ginimageApi/app/images/models" "ginimageApi/configs" "github.com/gin-gonic/gin" "gorm.io/driver/sqlite" "gorm.io/gorm" ) func setupImageHandlersTestDB(t *testing.T) { t.Helper() prev := configs.DB dsn := "file:" + t.Name() + "?mode=memory&cache=shared" db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{}) if err != nil { t.Fatalf("sqlite open failed: %v", err) } if err := db.AutoMigrate(&imageModels.Image{}); err != nil { t.Fatalf("migrate failed: %v", err) } configs.DB = db t.Cleanup(func() { if sqlDB, err := db.DB(); err == nil { _ = sqlDB.Close() } configs.DB = prev }) } func withUser(userID uint) gin.HandlerFunc { return func(c *gin.Context) { c.Set("user_id", userID) c.Next() } } func TestProcessRequiresFile(t *testing.T) { gin.SetMode(gin.TestMode) r := gin.New() r.POST("/images/process", Process) req := httptest.NewRequest(http.MethodPost, "/images/process", nil) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Fatalf("expected 400, got %d", w.Code) } } func TestProcessRejectsInvalidWidth(t *testing.T) { gin.SetMode(gin.TestMode) r := gin.New() r.POST("/images/process", Process) var body bytes.Buffer writer := multipart.NewWriter(&body) filePart, err := writer.CreateFormFile("file", "dummy.jpg") if err != nil { t.Fatalf("failed to create form file: %v", err) } _, _ = filePart.Write([]byte("not-a-real-image")) _ = writer.WriteField("width", "abc") if err := writer.Close(); err != nil { t.Fatalf("failed to close writer: %v", err) } req := httptest.NewRequest(http.MethodPost, "/images/process", &body) req.Header.Set("Content-Type", writer.FormDataContentType()) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Fatalf("expected 400, got %d", w.Code) } } func TestListImagesReturnsOnlyCurrentUser(t *testing.T) { gin.SetMode(gin.TestMode) setupImageHandlersTestDB(t) seed := []imageModels.Image{ {UserID: 1, Filename: "a.avif", PublicPath: "/uploads/processed/a.avif", MimeType: "image/avif", Size: 10, Format: "avif", Quality: 90}, {UserID: 1, Filename: "b.avif", PublicPath: "/uploads/processed/b.avif", MimeType: "image/avif", Size: 11, Format: "avif", Quality: 90}, {UserID: 2, Filename: "c.avif", PublicPath: "/uploads/processed/c.avif", MimeType: "image/avif", Size: 12, Format: "avif", Quality: 90}, } if err := configs.DB.Create(&seed).Error; err != nil { t.Fatalf("seed failed: %v", err) } r := gin.New() r.GET("/images", withUser(1), ListImages) req := httptest.NewRequest(http.MethodGet, "/images", nil) req.Host = "localhost:8080" w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d body=%s", w.Code, w.Body.String()) } var resp struct { Count int `json:"count"` Items []struct { ID uint `json:"id"` } `json:"items"` } if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { t.Fatalf("json parse failed: %v", err) } if resp.Count != 2 || len(resp.Items) != 2 { t.Fatalf("expected 2 images for current user, got count=%d len=%d", resp.Count, len(resp.Items)) } } func TestGetImageRejectsOtherUsersImage(t *testing.T) { gin.SetMode(gin.TestMode) setupImageHandlersTestDB(t) img := imageModels.Image{UserID: 2, Filename: "x.avif", PublicPath: "/uploads/processed/x.avif", MimeType: "image/avif", Size: 5, Format: "avif", Quality: 90} if err := configs.DB.Create(&img).Error; err != nil { t.Fatalf("seed failed: %v", err) } r := gin.New() r.GET("/images/:id", withUser(1), GetImage) w := httptest.NewRecorder() r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/images/1", nil)) if w.Code != http.StatusNotFound { t.Fatalf("expected 404, got %d", w.Code) } }