aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/game/service_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/game/service_test.go')
-rw-r--r--backend/game/service_test.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/backend/game/service_test.go b/backend/game/service_test.go
index 95ceef6..93e62f7 100644
--- a/backend/game/service_test.go
+++ b/backend/game/service_test.go
@@ -1,12 +1,31 @@
package game
import (
+ "context"
"testing"
"time"
"github.com/jackc/pgx/v5/pgtype"
+
+ "albatross-2026-backend/db"
)
+// stubQuerier implements db.Querier with only the methods needed for tests.
+// All unimplemented methods panic so missing stubs are caught immediately.
+type stubQuerier struct {
+ db.Querier
+ getGameByID func(ctx context.Context, gameID int32) (db.GetGameByIDRow, error)
+ getLatestStatesOfMainPlayers func(ctx context.Context, gameID int32) ([]db.GetLatestStatesOfMainPlayersRow, error)
+}
+
+func (s *stubQuerier) GetGameByID(ctx context.Context, gameID int32) (db.GetGameByIDRow, error) {
+ return s.getGameByID(ctx, gameID)
+}
+
+func (s *stubQuerier) GetLatestStatesOfMainPlayers(ctx context.Context, gameID int32) ([]db.GetLatestStatesOfMainPlayersRow, error) {
+ return s.getLatestStatesOfMainPlayers(ctx, gameID)
+}
+
func TestIsGameRunning(t *testing.T) {
now := time.Now()
tests := []struct {
@@ -80,3 +99,96 @@ func TestIsGameFinished(t *testing.T) {
})
}
}
+
+func TestGetWatchLatestStates_ParticipantRestriction(t *testing.T) {
+ now := time.Now()
+ var playerID int32 = 1
+ var otherID int32 = 2
+
+ code := "<?php echo 1;"
+ status := "pass"
+ var codeSize int32 = 14
+
+ mainPlayerRows := []db.GetLatestStatesOfMainPlayersRow{
+ {
+ GameID: 1,
+ UserID: playerID,
+ Code: &code,
+ Status: &status,
+ CodeSize: &codeSize,
+ },
+ {
+ GameID: 1,
+ UserID: otherID,
+ Code: &code,
+ Status: &status,
+ CodeSize: &codeSize,
+ },
+ }
+
+ tests := []struct {
+ name string
+ startedAt pgtype.Timestamp
+ userID *int32
+ isAdmin bool
+ wantErr error
+ }{
+ {
+ name: "participant blocked while game is running",
+ startedAt: pgtype.Timestamp{Time: now.Add(-1 * time.Minute), Valid: true},
+ userID: &playerID,
+ isAdmin: false,
+ wantErr: ErrForbidden,
+ },
+ {
+ name: "participant allowed after game finished",
+ startedAt: pgtype.Timestamp{Time: now.Add(-10 * time.Minute), Valid: true},
+ userID: &playerID,
+ isAdmin: false,
+ wantErr: nil,
+ },
+ {
+ name: "participant blocked before game starts",
+ startedAt: pgtype.Timestamp{Valid: false},
+ userID: &playerID,
+ isAdmin: false,
+ wantErr: ErrForbidden,
+ },
+ {
+ name: "admin always allowed even while running",
+ startedAt: pgtype.Timestamp{Time: now.Add(-1 * time.Minute), Valid: true},
+ userID: &playerID,
+ isAdmin: true,
+ wantErr: nil,
+ },
+ {
+ name: "non-participant allowed while running",
+ startedAt: pgtype.Timestamp{Time: now.Add(-1 * time.Minute), Valid: true},
+ userID: nil,
+ isAdmin: false,
+ wantErr: nil,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q := &stubQuerier{
+ getGameByID: func(_ context.Context, _ int32) (db.GetGameByIDRow, error) {
+ return db.GetGameByIDRow{
+ StartedAt: tt.startedAt,
+ DurationSeconds: 300,
+ }, nil
+ },
+ getLatestStatesOfMainPlayers: func(_ context.Context, _ int32) ([]db.GetLatestStatesOfMainPlayersRow, error) {
+ return mainPlayerRows, nil
+ },
+ }
+ svc := NewService(q, nil, nil)
+
+ _, err := svc.GetWatchLatestStates(context.Background(), 1, tt.userID, tt.isAdmin)
+ if err != tt.wantErr {
+ t.Errorf("got err=%v, want %v", err, tt.wantErr)
+ }
+ })
+ }
+}