package infra import ( "bytes" "encoding/json" "mime/multipart" "net/http" "net/http/httptest" "testing" ) // buildPNGMultipart crea un multipart con un campo "file" cuyo contenido tiene // los magic bytes de PNG (suficientes para que FileValidateType los reconozca). func buildPNGMultipart(t *testing.T, filename string, body string) (string, *bytes.Buffer) { t.Helper() var buf bytes.Buffer w := multipart.NewWriter(&buf) part, err := w.CreateFormFile("file", filename) if err != nil { t.Fatalf("CreateFormFile: %v", err) } // Magic bytes PNG: 89 50 4E 47 0D 0A 1A 0A part.Write([]byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}) part.Write([]byte(body)) w.Close() return w.FormDataContentType(), &buf } func TestUploadHandler(t *testing.T) { t.Run("acepta upload con imagen y responde JSON", func(t *testing.T) { dir := t.TempDir() cfg := StorageConfig{ BaseDir: dir, MaxFileSize: 1 << 20, AllowedTypes: []string{"image/png"}, } ct, body := buildPNGMultipart(t, "foto.png", "data extra") req := httptest.NewRequest("POST", "/upload", body) req.Header.Set("Content-Type", ct) rec := httptest.NewRecorder() UploadHandler(cfg).ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("got %d, body=%s", rec.Code, rec.Body.String()) } var resp struct { Files []UploadedFile `json:"files"` } if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { t.Fatalf("unmarshal: %v", err) } if len(resp.Files) != 1 { t.Fatalf("got %d files, want 1", len(resp.Files)) } if resp.Files[0].ContentType != "image/png" { t.Errorf("got ContentType %q", resp.Files[0].ContentType) } }) t.Run("rechaza tipo no permitido con 415", func(t *testing.T) { dir := t.TempDir() cfg := StorageConfig{ BaseDir: dir, MaxFileSize: 1 << 20, AllowedTypes: []string{"application/pdf"}, // PNG no en lista } ct, body := buildPNGMultipart(t, "foto.png", "x") req := httptest.NewRequest("POST", "/upload", body) req.Header.Set("Content-Type", ct) rec := httptest.NewRecorder() UploadHandler(cfg).ServeHTTP(rec, req) if rec.Code != http.StatusUnsupportedMediaType { t.Errorf("got %d, want 415", rec.Code) } }) t.Run("rechaza body que excede MaxFileSize con 400", func(t *testing.T) { dir := t.TempDir() cfg := StorageConfig{ BaseDir: dir, MaxFileSize: 10, // muy pequeno AllowedTypes: []string{"image/png"}, } ct, body := buildPNGMultipart(t, "foto.png", "muchos bytes extra para superar 10") req := httptest.NewRequest("POST", "/upload", body) req.Header.Set("Content-Type", ct) rec := httptest.NewRecorder() UploadHandler(cfg).ServeHTTP(rec, req) if rec.Code != http.StatusBadRequest { t.Errorf("got %d, want 400", rec.Code) } }) }