package http // handler_unit_test.go contains backend tests for package behavior, error paths, and regressions. import ( "bytes" "net/http" "net/http/httptest" "testing" "github.com/gofiber/fiber/v3" "knowfoolery/backend/shared/infra/utils/validation" ) // TestUpdateAuthAndValidationBranches ensures update auth and validation branches behavior is handled correctly. func TestUpdateAuthAndValidationBranches(t *testing.T) { h := NewHandler(nil, validation.NewValidator(), nil, nil, true, 20, 100) app := fiber.New() app.Post("/leaderboard/update", h.Update) req := httptest.NewRequest(http.MethodPost, "/leaderboard/update", bytes.NewReader([]byte(`{}`))) res, err := app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } defer res.Body.Close() if res.StatusCode != http.StatusForbidden { t.Fatalf("expected forbidden without auth claims, got %d", res.StatusCode) } app = fiber.New() app.Use(func(c fiber.Ctx) error { c.Locals("user_id", "user-1") c.Locals("user_roles", []string{"player"}) return c.Next() }) app.Post("/leaderboard/update", h.Update) req = httptest.NewRequest(http.MethodPost, "/leaderboard/update", bytes.NewReader([]byte(`{}`))) res, err = app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } defer res.Body.Close() if res.StatusCode != http.StatusForbidden { t.Fatalf("expected forbidden for non-service/non-admin, got %d", res.StatusCode) } app = fiber.New() app.Use(func(c fiber.Ctx) error { c.Locals("user_id", "svc-1") c.Locals("user_roles", []string{"service"}) return c.Next() }) app.Post("/leaderboard/update", h.Update) req = httptest.NewRequest(http.MethodPost, "/leaderboard/update", bytes.NewReader([]byte("{"))) req.Header.Set("Content-Type", "application/json") res, err = app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } defer res.Body.Close() if res.StatusCode != http.StatusBadRequest { t.Fatalf("expected bad request for malformed json, got %d", res.StatusCode) } validShape := `{ "session_id":"s1", "player_id":"u1", "player_name":"P", "total_score":1, "questions_asked":1, "questions_correct":1, "hints_used":0, "duration_seconds":10, "completed_at":"not-rfc3339", "completion_type":"completed" }` req = httptest.NewRequest(http.MethodPost, "/leaderboard/update", bytes.NewReader([]byte(validShape))) req.Header.Set("Content-Type", "application/json") res, err = app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } defer res.Body.Close() if res.StatusCode != http.StatusBadRequest { t.Fatalf("expected bad request for completed_at format, got %d", res.StatusCode) } } // TestGetPlayerRankingForbiddenBranch ensures get player ranking forbidden branch behavior is handled correctly. func TestGetPlayerRankingForbiddenBranch(t *testing.T) { h := NewHandler(nil, validation.NewValidator(), nil, nil, false, 20, 100) app := fiber.New() app.Use(func(c fiber.Ctx) error { c.Locals("user_id", "user-2") c.Locals("user_roles", []string{"player"}) return c.Next() }) app.Get("/leaderboard/players/:id", h.GetPlayerRanking) req := httptest.NewRequest(http.MethodGet, "/leaderboard/players/user-1?page=oops&page_size=-1", nil) res, err := app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } defer res.Body.Close() if res.StatusCode != http.StatusForbidden { t.Fatalf("expected forbidden for non-owner non-admin, got %d", res.StatusCode) } } // TestHelperFunctions ensures helper functions behavior is handled correctly. func TestHelperFunctions(t *testing.T) { if got := atoiWithDefault("", 3); got != 3 { t.Fatalf("expected default for empty input") } if got := atoiWithDefault("bad", 4); got != 4 { t.Fatalf("expected default for invalid input") } if got := atoiWithDefault("7", 4); got != 7 { t.Fatalf("expected parsed int") } }