use distinct types for player and session ids

This commit is contained in:
Branden J Brown 2024-01-31 22:40:12 -06:00
parent d61c70da86
commit 73b5ac7960
8 changed files with 42 additions and 32 deletions

View File

@ -3,14 +3,16 @@ package game
import ( import (
"testing" "testing"
"github.com/google/uuid"
"git.sunturtle.xyz/studio/shotgun/player" "git.sunturtle.xyz/studio/shotgun/player"
"git.sunturtle.xyz/studio/shotgun/serve" "git.sunturtle.xyz/studio/shotgun/serve"
) )
func TestNewGame(t *testing.T) { func TestNewGame(t *testing.T) {
t.Parallel() t.Parallel()
dealer := player.ID{1} dealer := player.ID{UUID: uuid.UUID{1}}
chall := player.ID{2} chall := player.ID{UUID: uuid.UUID{2}}
for i := 0; i < 10000; i++ { for i := 0; i < 10000; i++ {
g := New(dealer, chall) g := New(dealer, chall)
checks := []struct { checks := []struct {
@ -41,7 +43,7 @@ func TestNewGame(t *testing.T) {
func TestGameStartRound(t *testing.T) { func TestGameStartRound(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) g := New(player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}})
for i := int8(1); i < 100; i++ { for i := int8(1); i < 100; i++ {
checks := []struct { checks := []struct {
failed bool failed bool
@ -77,7 +79,7 @@ func TestGameStartRound(t *testing.T) {
func TestGameStartGroup(t *testing.T) { func TestGameStartGroup(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) g := New(player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}})
for i := uint(1); i < 10000; i++ { for i := uint(1); i < 10000; i++ {
checks := []struct { checks := []struct {
failed bool failed bool
@ -114,7 +116,7 @@ func TestGameStartGroup(t *testing.T) {
func TestGameNextTurn(t *testing.T) { func TestGameNextTurn(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) g := New(player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}})
for i := int8(1); i < 100; i++ { for i := int8(1); i < 100; i++ {
checks := []struct { checks := []struct {
failed bool failed bool
@ -143,8 +145,8 @@ func TestGameNextTurn(t *testing.T) {
func TestGamePlayers(t *testing.T) { func TestGamePlayers(t *testing.T) {
t.Parallel() t.Parallel()
dealer := player.ID{1} dealer := player.ID{UUID: uuid.UUID{1}}
chall := player.ID{2} chall := player.ID{UUID: uuid.UUID{2}}
g := New(dealer, chall) g := New(dealer, chall)
if g.CurrentPlayer().id != chall { if g.CurrentPlayer().id != chall {
t.Errorf("challenger isn't current player at start") t.Errorf("challenger isn't current player at start")
@ -183,7 +185,7 @@ func TestGamePlayers(t *testing.T) {
func TestGamePopShell(t *testing.T) { func TestGamePopShell(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) g := New(player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}})
if live := g.popShell(); live != g.shellArray[0] { if live := g.popShell(); live != g.shellArray[0] {
t.Errorf("first pop %t, wanted %t", live, g.shellArray[0]) t.Errorf("first pop %t, wanted %t", live, g.shellArray[0])
} }
@ -208,8 +210,8 @@ func TestGamePopShell(t *testing.T) {
} }
func TestGamePeek(t *testing.T) { func TestGamePeek(t *testing.T) {
dealer := player.ID{1} dealer := player.ID{UUID: uuid.UUID{1}}
chall := player.ID{2} chall := player.ID{UUID: uuid.UUID{2}}
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
t.Parallel() t.Parallel()
g := New(dealer, chall) g := New(dealer, chall)
@ -270,8 +272,8 @@ func TestGameEmpty(t *testing.T) {
func TestGameWinner(t *testing.T) { func TestGameWinner(t *testing.T) {
t.Parallel() t.Parallel()
dealer := player.ID{1} dealer := player.ID{UUID: uuid.UUID{1}}
chall := player.ID{2} chall := player.ID{UUID: uuid.UUID{2}}
cases := []struct { cases := []struct {
name string name string
p0, p1 int8 p0, p1 int8
@ -311,8 +313,8 @@ func TestGameWinner(t *testing.T) {
} }
func TestGameShoot(t *testing.T) { func TestGameShoot(t *testing.T) {
dealer := player.ID{1} dealer := player.ID{UUID: uuid.UUID{1}}
chall := player.ID{2} chall := player.ID{UUID: uuid.UUID{2}}
cases := []struct { cases := []struct {
name string name string
live bool live bool
@ -399,7 +401,7 @@ func TestGameShoot(t *testing.T) {
} }
func TestConcede(t *testing.T) { func TestConcede(t *testing.T) {
dealer, chall := player.ID{1}, player.ID{2} dealer, chall := player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}}
cases := []struct { cases := []struct {
name string name string
p player.ID p player.ID
@ -417,7 +419,7 @@ func TestConcede(t *testing.T) {
}, },
{ {
name: "neither", name: "neither",
p: player.ID{3}, p: player.ID{UUID: uuid.UUID{3}},
winner: player.ID{}, winner: player.ID{},
}, },
} }
@ -436,7 +438,7 @@ func TestConcede(t *testing.T) {
func TestGameDTO(t *testing.T) { func TestGameDTO(t *testing.T) {
t.Parallel() t.Parallel()
dealer, chall := player.ID{1}, player.ID{2} dealer, chall := player.ID{UUID: uuid.UUID{1}}, player.ID{UUID: uuid.UUID{2}}
g := New(dealer, chall) g := New(dealer, chall)
{ {
want := serve.Game{ want := serve.Game{

View File

@ -5,6 +5,8 @@ import (
"sync/atomic" "sync/atomic"
"testing" "testing"
"github.com/google/uuid"
"git.sunturtle.xyz/studio/shotgun/lobby" "git.sunturtle.xyz/studio/shotgun/lobby"
"git.sunturtle.xyz/studio/shotgun/player" "git.sunturtle.xyz/studio/shotgun/player"
) )
@ -20,7 +22,7 @@ func TestQueue(t *testing.T) {
for i := 0; i < N; i++ { for i := 0; i < N; i++ {
i := i i := i
go func() { go func() {
id, _, deal := l.Queue(context.Background(), player.ID{uint8(i), uint8(i >> 8)}) id, _, deal := l.Queue(context.Background(), player.ID{UUID: uuid.UUID{uint8(i), uint8(i >> 8)}})
if deal { if deal {
dealers.Add(1) dealers.Add(1)
} else { } else {

View File

@ -85,7 +85,7 @@ func Login(ctx context.Context, db RowQuerier, user, pass string) (ID, error) {
slog.ErrorContext(ctx, "login failed", "user", user) slog.ErrorContext(ctx, "login failed", "user", user)
return ID{}, fmt.Errorf("invalid credentials") return ID{}, fmt.Errorf("invalid credentials")
} }
return ID(id), nil return ID{id}, nil
} }
const initUsers = `CREATE TABLE shotgun_users ( const initUsers = `CREATE TABLE shotgun_users (

View File

@ -31,7 +31,7 @@ func TestLogin(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("logging in nonexistent user didn't err") t.Errorf("logging in nonexistent user didn't err")
} }
if id != uuid.Nil { if id.UUID != uuid.Nil {
t.Errorf("got nonzero user %v before registering", id) t.Errorf("got nonzero user %v before registering", id)
} }
@ -43,7 +43,7 @@ func TestLogin(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("couldn't login after registering: %v", err) t.Errorf("couldn't login after registering: %v", err)
} }
if id == uuid.Nil { if id.UUID == uuid.Nil {
t.Errorf("got zero player id after registering") t.Errorf("got zero player id after registering")
} }
@ -51,7 +51,7 @@ func TestLogin(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("logged in with wrong password") t.Errorf("logged in with wrong password")
} }
if wrong != uuid.Nil { if wrong.UUID != uuid.Nil {
t.Errorf("got nonzero user %v with wrong password (real is %v)", wrong, id) t.Errorf("got nonzero user %v with wrong password (real is %v)", wrong, id)
} }
} }

View File

@ -4,4 +4,6 @@ package player
import "github.com/google/uuid" import "github.com/google/uuid"
// ID is a unique ID for a player. // ID is a unique ID for a player.
type ID = uuid.UUID type ID struct {
uuid.UUID
}

View File

@ -11,7 +11,9 @@ import (
) )
// Session is a session ID. // Session is a session ID.
type Session = uuid.UUID type Session struct {
uuid.UUID
}
// InitSessions initializes an SQLite table relating player IDs to sessions. // InitSessions initializes an SQLite table relating player IDs to sessions.
func InitSessions(ctx context.Context, db Execer) error { func InitSessions(ctx context.Context, db Execer) error {
@ -32,7 +34,7 @@ func StartSession(ctx context.Context, db Execer, p ID, now time.Time) (Session,
return Session{}, fmt.Errorf("couldn't start session: %w", err) return Session{}, fmt.Errorf("couldn't start session: %w", err)
} }
slog.InfoContext(ctx, "session started", "player", p, "session", id, "now", now) slog.InfoContext(ctx, "session started", "player", p, "session", id, "now", now)
return Session(id), nil return Session{id}, nil
} }
// FromSession gets the player ID associated with a session and updates the // FromSession gets the player ID associated with a session and updates the

View File

@ -27,13 +27,13 @@ func TestSessions(t *testing.T) {
t.Fatalf("couldn't init sessions: %v", err) t.Fatalf("couldn't init sessions: %v", err)
} }
p := player.ID{1} p := player.ID{uuid.UUID{1}}
now := time.Unix(0, 0) now := time.Unix(0, 0)
id, err := player.StartSession(ctx, conn, p, now) id, err := player.StartSession(ctx, conn, p, now)
if err != nil { if err != nil {
t.Fatalf("couldn't start session: %v", err) t.Fatalf("couldn't start session: %v", err)
} }
if id == uuid.Nil { if id.UUID == uuid.Nil {
t.Errorf("got zero session id at start") t.Errorf("got zero session id at start")
} }
@ -41,7 +41,7 @@ func TestSessions(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("no error on expired session") t.Errorf("no error on expired session")
} }
if u != uuid.Nil { if u.UUID != uuid.Nil {
t.Errorf("got nonzero player %v from expired session", u) t.Errorf("got nonzero player %v from expired session", u)
} }
@ -49,7 +49,7 @@ func TestSessions(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("couldn't get player from session: %v", err) t.Errorf("couldn't get player from session: %v", err)
} }
if u == uuid.Nil { if u.UUID == uuid.Nil {
t.Errorf("got zero player from session") t.Errorf("got zero player from session")
} }
@ -57,7 +57,7 @@ func TestSessions(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("couldn't get player from extended session: %v", err) t.Errorf("couldn't get player from extended session: %v", err)
} }
if u == uuid.Nil { if u.UUID == uuid.Nil {
t.Errorf("got zero player from extended session") t.Errorf("got zero player from extended session")
} }
@ -69,7 +69,7 @@ func TestSessions(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("no error on logged out session") t.Errorf("no error on logged out session")
} }
if u != uuid.Nil { if u.UUID != uuid.Nil {
t.Errorf("got nonzero player %v from logged out session", u) t.Errorf("got nonzero player %v from logged out session", u)
} }
} }

View File

@ -6,6 +6,8 @@ import (
"net/netip" "net/netip"
"strings" "strings"
"github.com/google/uuid"
"git.sunturtle.xyz/studio/shotgun/player" "git.sunturtle.xyz/studio/shotgun/player"
) )
@ -21,7 +23,7 @@ func WithPlayerID(next http.Handler) http.Handler {
http.Error(w, "missing or invalid X-Forwarded-For header; check server configuration", http.StatusInternalServerError) http.Error(w, "missing or invalid X-Forwarded-For header; check server configuration", http.StatusInternalServerError)
return return
} }
id := player.ID(addr.As16()) id := player.ID{UUID: uuid.UUID(addr.As16())}
ctx := ctxWith(r.Context(), id) ctx := ctxWith(r.Context(), id)
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
}) })