diff --git a/cmd/server/games.go b/cmd/server/games.go index 109aa94..978f1d6 100644 --- a/cmd/server/games.go +++ b/cmd/server/games.go @@ -179,6 +179,24 @@ func (EventPlayerLeave) event() {} func (EventGameComplete) event() {} func (EventAssignmentRotation) event() {} +func EventWithTime(event Event, t time.Time) Event { + switch e := event.(type) { + case EventPlayerJoin: + e.Timestamp = t + event = e + case EventPlayerLeave: + e.Timestamp = t + event = e + case EventGameComplete: + e.Timestamp = t + event = e + case EventAssignmentRotation: + e.Timestamp = t + event = e + } + return event +} + func (games Games) GameEvents(ctx context.Context, id string, since time.Time) ([]Event, error) { var results []Event err := games.db.Query(ctx, func(rows *sql.Rows) error { @@ -212,23 +230,19 @@ func parseEvent(b []byte, timestamp time.Time) (Event, error) { case PlayerJoin: var v EventPlayerJoin err := json.Unmarshal(b, &v) - v.Timestamp = timestamp - return v, err + return EventWithTime(v, timestamp), err case PlayerLeave: var v EventPlayerLeave err := json.Unmarshal(b, &v) - v.Timestamp = timestamp - return v, err + return EventWithTime(v, timestamp), err case GameComplete: var v EventGameComplete err := json.Unmarshal(b, &v) - v.Timestamp = timestamp - return v, err + return EventWithTime(v, timestamp), err case AssignmentRotation: var v EventAssignmentRotation err := json.Unmarshal(b, &v) - v.Timestamp = timestamp - return v, err + return EventWithTime(v, timestamp), err } return nil, fmt.Errorf("unknown event type %d: %s", peek.Type, b) } @@ -453,7 +467,7 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string, // TODO generate .Global=...us major cities?, .Assignments.Public=...?, .Assignments.Private=holiday for k, v := range event.KillWords { if v.Global.Word == "" { - v.Global = KillWord{Word: randGlobal(), Points: 1} + v.Global = KillWord{Word: randGlobal(), Points: -1} } if len(v.Assignment.Public) == 0 { v.Assignment.Public = []KillWord{ diff --git a/cmd/server/games_test.go b/cmd/server/games_test.go index 97a1093..9510c8f 100644 --- a/cmd/server/games_test.go +++ b/cmd/server/games_test.go @@ -2,8 +2,10 @@ package main import ( "context" + "encoding/json" "fmt" "testing" + "time" ) func newTestGames(t *testing.T) Games { @@ -66,15 +68,41 @@ func TestGames(t *testing.T) { } if name, err := games.UserName(ctx, p); err != nil { t.Fatal(p, "err getting user name", err) - } else if name == "" { - t.Fatal("name empty") + } else if name != "player "+p { + t.Fatal("name wrong", name) + } + if err := games.UpdateUserName(ctx, p, "player! "+p); err != nil { + t.Fatal(p, "failed to rename:", err) + } else if name, err := games.UserName(ctx, p); err != nil { + t.Fatal(p, "err getting user name", err) + } else if name != "player! "+p { + t.Fatal("updated name wrong", name) } } + if events, err := games.GameEvents(ctx, id, time.Time{}); err != nil { + t.Fatal("failed to get player join, leave events:", err) + } else if len(events) != 6 { + t.Error("wrong number of events:", len(events)) + } + + now := time.Now() if err := games.CreateEventAssignmentRotation(ctx, id, "", "", "", 1); err != nil { t.Fatal("err creating rotation:", err) } + if events, err := games.GameEvents(ctx, id, time.Time{}); err != nil { + t.Fatal("failed to get player join, leave events:", err) + } else if len(events) != 7 { + t.Error("wrong number of events:", len(events)) + } else if events, err = games.GameEvents(ctx, id, now); err != nil { + t.Fatal("failed to get assignment rotation event:", err) + } else if len(events) != 1 { + t.Error("wrong number of events:", len(events)) + } else if _, ok := events[0].(EventAssignmentRotation); !ok { + t.Errorf("not an assignment rotation event: %T", events[0]) + } + if v, err := games.GamesForUser(ctx, "p1"); err != nil { t.Error("err getting games for user:", err) } else if len(v) < 1 { @@ -96,6 +124,9 @@ func TestGames(t *testing.T) { } else { for i := 0; i < 4; i++ { p := fmt.Sprintf("p%d", i+1) + if v.Players[p].Points() != 0 { + t.Error("nonzero points after zero kills:", v.Players[p].Points()) + } if v.Players[p].KillWords.Global.Word == "" { t.Error(p, "no killwords.global") } else if v.Players[p].KillWords.Assigned.IsZero() { @@ -119,3 +150,66 @@ func TestGames(t *testing.T) { } }) } + +func TestParseEvent(t *testing.T) { + now := time.Now() + + cases := map[string]Event{ + "player join": EventPlayerJoin{ + Type: PlayerJoin, + ID: "x", + }, + "player leave": EventPlayerLeave{ + Type: PlayerLeave, + ID: "x", + }, + "game complete": EventGameComplete{ + Type: GameComplete, + }, + "assignment rotation": EventAssignmentRotation{ + Type: AssignmentRotation, + Killer: "x", + Victim: "y", + KillWord: KillWord{ + Word: "word", + Points: 1, + }, + KillWords: map[string]KillWords{ + "x": KillWords{ + Global: KillWord{ + Word: "a", + Points: -1, + }, + Assignee: "z", + Assigned: now, + Assignment: Assignment{ + Public: []KillWord{{ + Word: "word2", + Points: 2, + }}, + Private: []KillWord{{ + Word: "word3", + Points: 3, + }}, + }, + }, + }, + }, + } + + for name, d := range cases { + c := d + t.Run(name, func(t *testing.T) { + c := EventWithTime(c, now) + b, _ := json.Marshal(c) + got, err := parseEvent(b, now) + if err != nil { + t.Fatal(err) + } + gotb, _ := json.Marshal(got) + if string(b) != string(gotb) { + t.Errorf("expected (%T) %+v, but got (%T) %+v", c, c, got, got) + } + }) + } +}