package router_test import ( "encoding/json" "errors" "fmt" "net/http" "net/http/httptest" "testing" "galaxy/model/report" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGetBattleValidation(t *testing.T) { validUUID := uuid.New().String() for _, tc := range []struct { description string turn string battleID string expectStatus int }{ {"Negative turn", "-1", validUUID, http.StatusBadRequest}, {"Non-numeric turn", "abc", validUUID, http.StatusBadRequest}, {"Invalid uuid", "0", invalidId, http.StatusBadRequest}, } { t.Run(tc.description, func(t *testing.T) { e := &dummyExecutor{} r := setupRouterExecutor(e) w := httptest.NewRecorder() path := fmt.Sprintf("/api/v1/battle/%s/%s", tc.turn, tc.battleID) req, _ := http.NewRequest(http.MethodGet, path, nil) r.ServeHTTP(w, req) assert.Equal(t, tc.expectStatus, w.Code, w.Body) assert.Equal(t, uuid.Nil, e.FetchBattleID, "FetchBattle must not be called on validation error") }) } } func TestGetBattleFound(t *testing.T) { id := uuid.New() raceA := uuid.New() raceB := uuid.New() stored := &report.BattleReport{ ID: id, Planet: 42, PlanetName: "X-Prime", Races: map[int]uuid.UUID{ 0: raceA, 1: raceB, }, Ships: map[int]report.BattleReportGroup{ 10: { Race: "Alpha", ClassName: "Drone", Tech: map[string]report.Float{"WEAPONS": report.F(1)}, Number: 5, NumberLeft: 3, LoadType: "EMP", LoadQuantity: report.F(0), InBattle: true, }, 20: { Race: "Beta", ClassName: "Spy", Tech: map[string]report.Float{"SHIELDS": report.F(2)}, Number: 4, NumberLeft: 0, LoadType: "EMP", LoadQuantity: report.F(0), InBattle: true, }, }, Protocol: []report.BattleActionReport{ {Attacker: 0, AttackerShipClass: 10, Defender: 1, DefenderShipClass: 20, Destroyed: true}, }, } e := &dummyExecutor{ FetchBattleResult: stored, FetchBattleOK: true, } r := setupRouterExecutor(e) w := httptest.NewRecorder() path := fmt.Sprintf("/api/v1/battle/%d/%s", 7, id.String()) req, _ := http.NewRequest(http.MethodGet, path, nil) r.ServeHTTP(w, req) require.Equal(t, http.StatusOK, w.Code, w.Body) assert.Equal(t, uint(7), e.FetchBattleTurn) assert.Equal(t, id, e.FetchBattleID) var got report.BattleReport require.NoError(t, json.Unmarshal(w.Body.Bytes(), &got)) assert.Equal(t, stored.ID, got.ID) assert.Equal(t, stored.Planet, got.Planet) assert.Equal(t, stored.PlanetName, got.PlanetName) assert.Equal(t, stored.Races, got.Races) require.Len(t, got.Ships, len(stored.Ships)) assert.Equal(t, stored.Ships[10].ClassName, got.Ships[10].ClassName) assert.Equal(t, stored.Ships[20].NumberLeft, got.Ships[20].NumberLeft) require.Len(t, got.Protocol, 1) assert.Equal(t, stored.Protocol[0], got.Protocol[0]) } func TestGetBattleTurnZero(t *testing.T) { id := uuid.New() e := &dummyExecutor{ FetchBattleResult: &report.BattleReport{ID: id}, FetchBattleOK: true, } r := setupRouterExecutor(e) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/battle/0/%s", id.String()), nil) r.ServeHTTP(w, req) require.Equal(t, http.StatusOK, w.Code, w.Body) assert.Equal(t, uint(0), e.FetchBattleTurn) assert.Equal(t, id, e.FetchBattleID) } func TestGetBattleNotFound(t *testing.T) { id := uuid.New() e := &dummyExecutor{FetchBattleOK: false} r := setupRouterExecutor(e) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/battle/3/%s", id.String()), nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusNotFound, w.Code, w.Body) assert.Equal(t, uint(3), e.FetchBattleTurn) assert.Equal(t, id, e.FetchBattleID) } func TestGetBattleEngineError(t *testing.T) { e := &dummyExecutor{FetchBattleErr: errors.New("engine boom")} r := setupRouterExecutor(e) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/battle/3/%s", uuid.NewString()), nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code, w.Body) }