package api import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestWriteError(t *testing.T) { rec := httptest.NewRecorder() WriteError(rec, http.StatusBadRequest, "nope") if rec.Code != http.StatusBadRequest { t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest) } contentType := rec.Header().Get("Content-Type") if !strings.HasPrefix(contentType, "application/json") { t.Fatalf("Content-Type = %q, want application/json", contentType) } var body map[string]string if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil { t.Fatalf("response is not valid JSON: %v", err) } if body["error"] != "nope" { t.Fatalf("error message = %q, want %q", body["error"], "nope") } } func TestWriteJSONNilPayload(t *testing.T) { rec := httptest.NewRecorder() WriteJSON(rec, http.StatusNoContent, nil) if rec.Code != http.StatusNoContent { t.Fatalf("status = %d, want %d", rec.Code, http.StatusNoContent) } if rec.Body.Len() != 0 { t.Fatalf("body = %q, want empty", rec.Body.String()) } } func TestDecodeJSON(t *testing.T) { type userRequest struct { Email string `json:"email"` Password string `json:"password"` } req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{"email":"alice@example.com","password":"hunter2"}`)) got, err := DecodeJSON[userRequest](req) if err != nil { t.Fatalf("DecodeJSON returned error: %v", err) } if got == nil || got.Email != "alice@example.com" || got.Password != "hunter2" { t.Fatalf("DecodeJSON = %+v, want alice@example.com/hunter2", got) } } func TestDecodeJSONInvalid(t *testing.T) { req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("not json")) _, err := DecodeJSON[struct{}](req) if err == nil { t.Fatal("DecodeJSON returned nil error for invalid body") } if err.Error() != "Failed to deserialize request" { t.Fatalf("error = %q, want %q", err.Error(), "Failed to deserialize request") } } func TestErrorSerializesToJSON(t *testing.T) { rec := httptest.NewRecorder() WriteJSON(rec, http.StatusConflict, Error{Err: "boom"}) if !strings.Contains(rec.Body.String(), `"boom"`) { t.Fatalf("body = %q, want it to contain the error message", rec.Body.String()) } }