From e71c002b779ad5d00d55ec8731c7b5929877bd43 Mon Sep 17 00:00:00 2001 From: Jesse Snyder Date: Wed, 11 Oct 2023 13:10:54 -0700 Subject: [PATCH 1/2] Copy Dallinger's way of doing things in fixtures --- test/conftest.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 3ad69d76..bcc17403 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -89,6 +89,10 @@ def stub_config(): for key in default_keys: config.register(*key) config.extend(defaults.copy()) + # Patch load() so we don't update any key/value pairs from actual files: + # (Note: this is blindly cargo-culted in from dallinger's equivalent fixture. + # Not certain it's necessary here.) + config.load = mock.Mock(side_effect=lambda: setattr(config, "ready", True)) config.ready = True return config @@ -99,12 +103,12 @@ def active_config(stub_config): """Loads the standard config as the active configuration returned by dallinger.config.get_config() and returns it. """ - from dallinger.config import get_config + from dallinger import config as c - config = get_config() - config.data = stub_config.data - config.ready = True - return config + orig_config = c.config + c.config = stub_config + yield c.config + c.config = orig_config @pytest.fixture From 8bf68ce17965252da91f7d8a7588eceab92db824 Mon Sep 17 00:00:00 2001 From: Jesse Snyder Date: Wed, 11 Oct 2023 13:11:56 -0700 Subject: [PATCH 2/2] Tests and fixes for gridworld [de]serialization --- dlgr/griduniverse/experiment.py | 13 +++++++---- test/test_gridworld.py | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/dlgr/griduniverse/experiment.py b/dlgr/griduniverse/experiment.py index e66e30b0..476bd5ca 100644 --- a/dlgr/griduniverse/experiment.py +++ b/dlgr/griduniverse/experiment.py @@ -567,12 +567,14 @@ def deserialize(self, state): self.players = {} for player_state in state["players"]: - player_state["color_name"] = player_state.pop("color", None) + # Avoid mutating the caller's data + new_state = player_state.copy() + new_state["color_name"] = new_state.pop("color", None) player = Player( pseudonym_locale=self.pseudonyms_locale, pseudonym_gender=self.pseudonyms_gender, grid=self, - **player_state, + **new_state, ) self.players[player.id] = player @@ -587,9 +589,12 @@ def deserialize(self, state): if "items" in state: self.item_locations = {} for item_state in state["items"]: - # TODO verify this works at some point! item_props = self.item_config[item_state["item_id"]] - obj = Item(item_config=item_props, **item_state) + invalid_params = ["item_id", "maturity"] + item_params = { + k: v for k, v in item_state.items() if k not in invalid_params + } + obj = Item(item_props, **item_params) self.item_locations[tuple(obj.position)] = obj def instructions(self): diff --git a/test/test_gridworld.py b/test/test_gridworld.py index 5a0c9726..3630acd0 100644 --- a/test/test_gridworld.py +++ b/test/test_gridworld.py @@ -23,6 +23,13 @@ def test_spawn_item_at_random(self, gridworld): assert gridworld.items_updated is True assert len(gridworld.item_locations.keys()) == 1 + def test_replenish_items_boosts_item_count_to_target(self, gridworld): + target = sum(item.get("item_count") for item in gridworld.item_config.values()) + + gridworld.replenish_items() + + target == len(gridworld.item_locations) + @pytest.mark.usefixtures("env") class TestSerialize(object): @@ -30,8 +37,14 @@ def test_serializes_players(self, gridworld): player = mock.Mock() player.serialize.return_value = "Serialized Player" gridworld.players = {1: player} + values = gridworld.serialize() + assert values["players"] == ["Serialized Player"] + + def test_serializes_game_state(self, gridworld): + values = gridworld.serialize() + assert values["round"] == 0 assert values["donation_active"] == gridworld.donation_active assert values["rows"] == gridworld.rows @@ -59,6 +72,34 @@ def test_food_and_wall_serialization_disabled(self, gridworld): assert values.get("food") is None +class TestDeserialize(object): + def test_round_trip(self, gridworld): + # Walls ("classic") + gridworld.walls_density = 0.0001 + gridworld.build_labyrinth() + # Items + gridworld.replenish_items() + # Players + gridworld.spawn_player(1) + gridworld.spawn_player(2) + + # Save state, so we can verify that we restore all the same values + saved = gridworld.serialize() + + # Clear everything, so we can verify it's restored via + # deserialization: + gridworld.wall_locations.clear() + gridworld.item_locations.clear() + gridworld.players.clear() + gridworld.round = None + + gridworld.deserialize(saved) + + refetched = gridworld.serialize() + + assert saved == refetched + + @pytest.mark.usefixtures("env") class TestRoundState(object): def test_check_round_not_started(self, gridworld):