From c26f22864e132a513cdb55b25fe7b8e8a787129b Mon Sep 17 00:00:00 2001 From: Rob O'Dwyer Date: Tue, 24 May 2022 15:17:21 -0700 Subject: [PATCH] add automated tests for all registered GameMap implementations --- maps/helpers_test.go | 74 ++++++++++++++++++++++--------------------- maps/registry.go | 6 ++++ maps/registry_test.go | 68 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 maps/registry_test.go diff --git a/maps/helpers_test.go b/maps/helpers_test.go index 3aa2c5d..5c37df2 100644 --- a/maps/helpers_test.go +++ b/maps/helpers_test.go @@ -19,11 +19,10 @@ func TestSetupBoard_Error(t *testing.T) { Id: t.Name(), Error: errors.New("bad map update"), } - RegisterMap(testMap.ID(), testMap) - - _, err := SetupBoard(testMap.ID(), rules.Settings{}, 10, 10, []string{}) - - require.EqualError(t, err, "bad map update") + TestMap(testMap.ID(), testMap, func() { + _, err := SetupBoard(testMap.ID(), rules.Settings{}, 10, 10, []string{}) + require.EqualError(t, err, "bad map update") + }) } func TestSetupBoard(t *testing.T) { @@ -42,26 +41,27 @@ func TestSetupBoard(t *testing.T) { {X: 2, Y: 2}, }, } - RegisterMap(testMap.ID(), testMap) - - boardState, err := SetupBoard(testMap.ID(), rules.Settings{}, 10, 10, []string{"1", "2"}) - - require.NoError(t, err) - - require.Len(t, boardState.Snakes, 2) - - require.Equal(t, rules.Snake{ - ID: "1", - Body: []rules.Point{{X: 3, Y: 4}, {X: 3, Y: 4}, {X: 3, Y: 4}}, - Health: rules.SnakeMaxHealth, - }, boardState.Snakes[0]) - require.Equal(t, rules.Snake{ - ID: "2", - Body: []rules.Point{{X: 6, Y: 2}, {X: 6, Y: 2}, {X: 6, Y: 2}}, - Health: rules.SnakeMaxHealth, - }, boardState.Snakes[1]) - require.Equal(t, []rules.Point{{X: 1, Y: 1}, {X: 5, Y: 3}}, boardState.Food) - require.Equal(t, []rules.Point{{X: 3, Y: 5}, {X: 2, Y: 2}}, boardState.Hazards) + + TestMap(testMap.ID(), testMap, func() { + boardState, err := SetupBoard(testMap.ID(), rules.Settings{}, 10, 10, []string{"1", "2"}) + + require.NoError(t, err) + + require.Len(t, boardState.Snakes, 2) + + require.Equal(t, rules.Snake{ + ID: "1", + Body: []rules.Point{{X: 3, Y: 4}, {X: 3, Y: 4}, {X: 3, Y: 4}}, + Health: rules.SnakeMaxHealth, + }, boardState.Snakes[0]) + require.Equal(t, rules.Snake{ + ID: "2", + Body: []rules.Point{{X: 6, Y: 2}, {X: 6, Y: 2}, {X: 6, Y: 2}}, + Health: rules.SnakeMaxHealth, + }, boardState.Snakes[1]) + require.Equal(t, []rules.Point{{X: 1, Y: 1}, {X: 5, Y: 3}}, boardState.Food) + require.Equal(t, []rules.Point{{X: 3, Y: 5}, {X: 2, Y: 2}}, boardState.Hazards) + }) } func TestUpdateBoard(t *testing.T) { @@ -80,7 +80,6 @@ func TestUpdateBoard(t *testing.T) { {X: 2, Y: 2}, }, } - RegisterMap(testMap.ID(), testMap) previousBoardState := &rules.BoardState{ Turn: 0, @@ -98,17 +97,20 @@ func TestUpdateBoard(t *testing.T) { }, }, } - boardState, err := UpdateBoard(testMap.ID(), previousBoardState, rules.Settings{}) - require.NoError(t, err) + TestMap(testMap.ID(), testMap, func() { + boardState, err := UpdateBoard(testMap.ID(), previousBoardState, rules.Settings{}) + + require.NoError(t, err) - require.Len(t, boardState.Snakes, 1) + require.Len(t, boardState.Snakes, 1) - require.Equal(t, rules.Snake{ - ID: "1", - Body: []rules.Point{{X: 6, Y: 4}, {X: 6, Y: 3}, {X: 6, Y: 2}}, - Health: rules.SnakeMaxHealth, - }, boardState.Snakes[0]) - require.Equal(t, []rules.Point{{X: 0, Y: 1}, {X: 1, Y: 1}, {X: 5, Y: 3}}, boardState.Food) - require.Equal(t, []rules.Point{{X: 3, Y: 4}, {X: 3, Y: 5}, {X: 2, Y: 2}}, boardState.Hazards) + require.Equal(t, rules.Snake{ + ID: "1", + Body: []rules.Point{{X: 6, Y: 4}, {X: 6, Y: 3}, {X: 6, Y: 2}}, + Health: rules.SnakeMaxHealth, + }, boardState.Snakes[0]) + require.Equal(t, []rules.Point{{X: 0, Y: 1}, {X: 1, Y: 1}, {X: 5, Y: 3}}, boardState.Food) + require.Equal(t, []rules.Point{{X: 3, Y: 4}, {X: 3, Y: 5}, {X: 2, Y: 2}}, boardState.Hazards) + }) } diff --git a/maps/registry.go b/maps/registry.go index 3c9fff8..de79de3 100644 --- a/maps/registry.go +++ b/maps/registry.go @@ -38,3 +38,9 @@ func GetMap(id string) (GameMap, error) { func RegisterMap(id string, m GameMap) { globalRegistry.RegisterMap(id, m) } + +func TestMap(id string, m GameMap, callback func()) { + globalRegistry[id] = m + callback() + delete(globalRegistry, id) +} diff --git a/maps/registry_test.go b/maps/registry_test.go new file mode 100644 index 0000000..6016108 --- /dev/null +++ b/maps/registry_test.go @@ -0,0 +1,68 @@ +package maps + +import ( + "testing" + + "github.com/BattlesnakeOfficial/rules" + "github.com/stretchr/testify/require" +) + +const maxBoardWidth, maxBoardHeight = 25, 25 + +var testSettings rules.Settings = rules.Settings{ + FoodSpawnChance: 25, + MinimumFood: 1, + HazardDamagePerTurn: 14, + RoyaleSettings: rules.RoyaleSettings{ + ShrinkEveryNTurns: 1, + }, +} + +func TestRegisteredMaps(t *testing.T) { + for mapName, gameMap := range globalRegistry { + t.Run(mapName, func(t *testing.T) { + require.Equalf(t, mapName, gameMap.ID(), "%#v game map doesn't return its own ID", mapName) + + var setupBoardState *rules.BoardState + + for width := 0; width < maxBoardWidth; width++ { + for height := 0; height < maxBoardHeight; height++ { + initialBoardState := rules.NewBoardState(width, height) + initialBoardState.Snakes = append(initialBoardState.Snakes, rules.Snake{ID: "1", Body: []rules.Point{}}) + initialBoardState.Snakes = append(initialBoardState.Snakes, rules.Snake{ID: "2", Body: []rules.Point{}}) + passedBoardState := initialBoardState.Clone() + tempBoardState := initialBoardState.Clone() + err := gameMap.SetupBoard(passedBoardState, testSettings, NewBoardStateEditor(tempBoardState)) + if err == nil { + setupBoardState = tempBoardState + require.Equal(t, initialBoardState, passedBoardState, "BoardState should not be modified directly by GameMap.SetupBoard") + break + } + } + } + require.NotNil(t, setupBoardState, "Map does not successfully setup the board at any supported combination of width and height") + require.NotNil(t, setupBoardState.Food) + require.NotNil(t, setupBoardState.Hazards) + require.NotNil(t, setupBoardState.Snakes) + for _, snake := range setupBoardState.Snakes { + require.NotEmpty(t, snake.Body, "Map should place all snakes by initializing their body") + } + + previousBoardState := rules.NewBoardState(rules.BoardSizeMedium, rules.BoardSizeMedium) + previousBoardState.Food = append(previousBoardState.Food, []rules.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}...) + previousBoardState.Hazards = append(previousBoardState.Food, []rules.Point{{X: 4, Y: 3}, {X: 2, Y: 1}}...) + previousBoardState.Snakes = append(previousBoardState.Snakes, rules.Snake{ + ID: "1", + Body: []rules.Point{{X: 5, Y: 5}, {X: 5, Y: 4}, {X: 5, Y: 3}}, + Health: 100, + }) + previousBoardState.Turn = 0 + + passedBoardState := previousBoardState.Clone() + tempBoardState := previousBoardState.Clone() + err := gameMap.UpdateBoard(passedBoardState, testSettings, NewBoardStateEditor(tempBoardState)) + require.NoError(t, err, "GameMap.UpdateBoard returned an error") + require.Equal(t, previousBoardState, passedBoardState, "BoardState should not be modified directly by GameMap.UpdateBoard") + }) + } +}