diff --git a/internal/beerpong-elo.go b/internal/beerpong-elo.go index 338efa1..cf55c88 100644 --- a/internal/beerpong-elo.go +++ b/internal/beerpong-elo.go @@ -31,7 +31,7 @@ func loadFromFile(repo repo.Repo, path string) error { return err } - var payload []model.InputGame + var payload []model.Game err = json.Unmarshal(content, &payload) if err != nil { return err diff --git a/internal/repo/inMemoryRepo.go b/internal/repo/inMemoryRepo.go index 44bb0ed..70daa29 100644 --- a/internal/repo/inMemoryRepo.go +++ b/internal/repo/inMemoryRepo.go @@ -9,76 +9,92 @@ import ( type InMemoryRepo struct { games []model.Game players []model.Player + results []model.GameResult } func NewInMemoryRepo() Repo { return &InMemoryRepo{ games: []model.Game{}, players: []model.Player{}, + results: []model.GameResult{}, } } -func (r *InMemoryRepo) AddGame(game model.InputGame) model.GameID { +func (r *InMemoryRepo) AddGame(game model.Game) (model.GameID, error) { id := len(r.games) - authID := r.GetOrCreatePlayerID(game.Author) - t0p0ID := r.GetOrCreatePlayerID(game.Team0Player0) - t0p1ID := r.GetOrCreatePlayerID(game.Team0Player1) - t1p0ID := r.GetOrCreatePlayerID(game.Team1Player0) - t1p1ID := r.GetOrCreatePlayerID(game.Team1Player1) - parsedGame := model.Game{ - ID: model.GameID(rune(id)), + ID: model.GameID(strconv.Itoa(id)), Added: game.Added, - Author: authID, - Team0Player0: t0p0ID, - Team0Player1: t0p1ID, - Team1Player0: t1p1ID, - Team1Player1: t1p0ID, + Author: game.Author, + Team0Player0: game.Team0Player0, + Team0Player1: game.Team0Player1, + Team1Player0: game.Team1Player0, + Team1Player1: game.Team1Player1, Score: game.Score, Overtime: game.Overtime, } r.games = append(r.games, parsedGame) - return model.GameID((rune(id))) + return model.GameID(strconv.Itoa(id)), nil } -func (r *InMemoryRepo) GetGame(id model.GameID) model.Game { +func (r *InMemoryRepo) GetGame(id model.GameID) (*model.Game, error) { i, err := strconv.Atoi(string(id)) if err != nil { - panic(err) + return nil, err } - return r.games[i] + return &r.games[i], nil } func (r *InMemoryRepo) GetAllGames() []model.Game { return r.games } -func (r *InMemoryRepo) GetOrCreatePlayerID(name string) model.PlayerID { +func (r *InMemoryRepo) GetOrCreatePlayerID(name string) (model.PlayerID, error) { id := model.PlayerID(name) for _, player := range r.players { if player.ID == id { - return id + return id, nil } } // No player found. Create one. r.players = append(r.players, model.NewPlayer(id)) - return id + return id, nil } -func (r *InMemoryRepo) GetPlayer(id model.PlayerID) *model.Player { +func (r *InMemoryRepo) GetPlayer(id model.PlayerID) (*model.Player, error) { for _, player := range r.players { if player.ID == id { - return &player + return &player, nil } } - return nil + return nil, nil +} + +func (r *InMemoryRepo) AddGameResult(result model.GameResult) (model.GameResultID, error) { + id := model.GameResultID(strconv.Itoa(len(r.results))) + + result.ID = id + + r.results = append(r.results, result) + + return id, nil +} + +func (r *InMemoryRepo) GetGameResult(id model.GameResultID) (*model.GameResult,error) { + i, err := strconv.Atoi(string(id)) + + if err != nil { + return nil,nil + } + + return &r.results[i],nil } diff --git a/internal/repo/repo.go b/internal/repo/repo.go index 814dc24..eb6a248 100644 --- a/internal/repo/repo.go +++ b/internal/repo/repo.go @@ -5,10 +5,21 @@ import ( ) type Repo interface { - AddGame(game model.InputGame) model.GameID - GetGame(id model.GameID) model.Game - GetAllGames() []model.Game + // Add a new game to the repo. ID needs to be nil on argument. PlayerID are fetched beforehand. + AddGame(model.Game) (model.GameID, error) - GetOrCreatePlayerID(name string) model.PlayerID - GetPlayer(id model.PlayerID) *model.Player + //Get a game by ID. Returns nil if not found. + GetGame(model.GameID) (*model.Game, error) + + // Get ID of a player. Creates one if not found. + GetOrCreatePlayerID(string) (model.PlayerID, error) + + // Get player by id. Returns nil if not found. + GetPlayer(model.PlayerID) (*model.Player, error) + + // Adds a game result. ID needs to be nil on argument. + AddGameResult(model.GameResult) (model.GameResultID, error) + + // Get a game result by ID. Returns nil if not found. + GetGameResult(model.GameResultID) (*model.GameResult, error) } diff --git a/internal/repo/repo_test.go b/internal/repo/repo_test.go new file mode 100644 index 0000000..91c11e0 --- /dev/null +++ b/internal/repo/repo_test.go @@ -0,0 +1,128 @@ +package repo_test + +import ( + "testing" + "time" + + "git.kapelle.org/niklas/beerpong-elo/internal/model" + "git.kapelle.org/niklas/beerpong-elo/internal/repo" + "github.com/stretchr/testify/assert" +) + +func createRepo() repo.Repo { + return repo.NewInMemoryRepo() +} + +func addGameToRepo(repo repo.Repo) model.GameID { + p1, _ := repo.GetOrCreatePlayerID("player1") + p2, _ := repo.GetOrCreatePlayerID("player2") + p3, _ := repo.GetOrCreatePlayerID("player3") + p4, _ := repo.GetOrCreatePlayerID("player4") + + id, _ := repo.AddGame(model.Game{ + Added: time.Date(2024, 6, 15, 12, 30, 31, 0, time.UTC), + Author: p1, + Team0Player0: p1, + Team0Player1: p2, + Team1Player0: p3, + Team1Player1: p4, + Score: 3, + Overtime: true, + }) + + return id +} + +func TestAddGame(t *testing.T) { + repo := createRepo() + + id := addGameToRepo(repo) + + retGame, err := repo.GetGame(id) + + assert.NoError(t, err) + + assert.Equal(t, id, retGame.ID, "Returned ID and ID of retrieved game are not the same") + assert.Equal(t, 3, retGame.Score, "Score is not the same") + assert.Equal(t, true, retGame.Overtime, "Overtime is not the same") + assert.Equal(t, time.Date(2024, 6, 15, 12, 30, 31, 0, time.UTC).Unix(), retGame.Added.Unix(), "Added time is not the same") +} + +func TestCreatePlayer(t *testing.T) { + repo := createRepo() + + id, err := repo.GetOrCreatePlayerID("player1") + + assert.NoError(t, err) + + player, err := repo.GetPlayer(id) + + assert.NoError(t, err) + assert.NotNil(t, player) +} + +func TestPlayerNotFound(t *testing.T) { + repo := createRepo() + + result, err := repo.GetPlayer("non existing") + + assert.NoError(t, err) + assert.Nil(t, result) +} + +func TestAddPlayer(t *testing.T) { + repo := createRepo() + + gameID := addGameToRepo(repo) + retGame, err := repo.GetGame(gameID) + assert.NoError(t, err) + + result, err := repo.GetPlayer(retGame.Team0Player0) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, retGame.Team0Player0, result.ID) + + result, err = repo.GetPlayer(retGame.Team0Player1) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, retGame.Team0Player1, result.ID) + + result, err = repo.GetPlayer(retGame.Team1Player0) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, retGame.Team1Player0, result.ID) + + result, err = repo.GetPlayer(retGame.Team1Player1) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, retGame.Team1Player1, result.ID) + + result, err = repo.GetPlayer(retGame.Author) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, retGame.Team0Player0, result.ID) +} + +func TestAddResult(t *testing.T) { + repo := createRepo() + + gameID := addGameToRepo(repo) + + retGame, err := repo.GetGame(gameID) + assert.NoError(t, err) + + gameResult := model.GameResult{ + Game: gameID, + Player: retGame.Team0Player0, + } + + gameResultID, err := repo.AddGameResult(gameResult) + assert.NoError(t, err) + + retResult, err := repo.GetGameResult(gameResultID) + + assert.NoError(t, err) + assert.NotNil(t, retResult) + assert.Equal(t, retGame.Team0Player0, retResult.Player, "PlayerID is not the same as the one used in the game") + assert.Equal(t, gameID, retResult.Game, "GameID is not the same as the added Game") +} diff --git a/internal/web/web.go b/internal/web/web.go index ff93822..bb14719 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -1,7 +1,6 @@ package web import ( - "encoding/json" "fmt" "net/http" @@ -15,13 +14,5 @@ func CreateWebserver(repo repo.Repo) *http.ServeMux { fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path) }) - router.HandleFunc("GET /games", func(w http.ResponseWriter, r *http.Request) { - games := repo.GetAllGames() - - w.Header().Set("Content-Type", "application/json") - - json.NewEncoder(w).Encode(games) - }) - return router }