package gifts import ( "context" "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "github.com/google/uuid" ) type fakeStore struct { gift PublicGift err error } func (f fakeStore) GetPublicBySlug(context.Context, string) (PublicGift, error) { return f.gift, f.err } func TestGetGiftReturnsPublicRepresentation(t *testing.T) { giftID := uuid.MustParse("11111111-1111-4111-8111-111111111111") itemID := uuid.MustParse("22222222-2222-4222-8222-222222222222") service := NewService(fakeStore{gift: PublicGift{ ID: giftID, Slug: "demo", RecipientName: "Anna", SenderName: "Alex", Title: "A little surprise for you", IntroMessage: "I made something for you.", RevealMessage: "A beautiful final note.", Items: []PublicGiftItem{{ ID: itemID, Type: "text", Title: "A note", Text: "Hello", SortOrder: 1, }}, }}) request := httptest.NewRequest(http.MethodGet, "/api/gifts/demo", nil) recorder := httptest.NewRecorder() NewHandler(service).Routes().ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("expected 200, got %d", recorder.Code) } if contentType := recorder.Header().Get("Content-Type"); contentType != "application/json; charset=utf-8" { t.Fatalf("unexpected content type: %q", contentType) } var response PublicGift if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { t.Fatalf("decode response: %v", err) } if response.RecipientName != "Anna" || len(response.Items) != 1 { t.Fatalf("unexpected response: %+v", response) } } func TestGetGiftReturnsNotFound(t *testing.T) { service := NewService(fakeStore{err: ErrNotFound}) request := httptest.NewRequest(http.MethodGet, "/api/gifts/missing", nil) recorder := httptest.NewRecorder() NewHandler(service).Routes().ServeHTTP(recorder, request) if recorder.Code != http.StatusNotFound { t.Fatalf("expected 404, got %d", recorder.Code) } if body := recorder.Body.String(); body != "{\"error\":\"gift not found\"}\n" { t.Fatalf("unexpected error body: %q", body) } } func TestGetGiftHidesStoreErrors(t *testing.T) { service := NewService(fakeStore{err: errors.New("database connection lost")}) request := httptest.NewRequest(http.MethodGet, "/api/gifts/demo", nil) recorder := httptest.NewRecorder() NewHandler(service).Routes().ServeHTTP(recorder, request) if recorder.Code != http.StatusInternalServerError { t.Fatalf("expected 500, got %d", recorder.Code) } if body := recorder.Body.String(); body != "{\"error\":\"could not load gift\"}\n" { t.Fatalf("unexpected error body: %q", body) } } func TestGetGiftRejectsInvalidSlug(t *testing.T) { service := NewService(fakeStore{}) request := httptest.NewRequest(http.MethodGet, "/api/gifts/not%20a%20slug", nil) recorder := httptest.NewRecorder() NewHandler(service).Routes().ServeHTTP(recorder, request) if recorder.Code != http.StatusBadRequest { t.Fatalf("expected 400, got %d", recorder.Code) } } func TestHealthReturnsOK(t *testing.T) { recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "/health", nil) NewHandler(NewService(fakeStore{})).Routes().ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("expected 200, got %d", recorder.Code) } if body := recorder.Body.String(); body != "{\"status\":\"ok\"}\n" { t.Fatalf("unexpected health body: %q", body) } } func TestServiceRejectsEmptySlug(t *testing.T) { service := NewService(fakeStore{}) _, err := service.GetPublicGift(context.Background(), "") if err != ErrNotFound { t.Fatalf("expected ErrNotFound, got %v", err) } }