diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 9c8f4d286..cf0ac95c6 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -1193,10 +1193,16 @@ def get_method_rates(self, obj): ) def get_encounters(self, obj): # get versions for later use - version_objects = Version.objects.all() - version_data = VersionSummarySerializer( - version_objects, many=True, context=self.context - ).data + version_objects = Version.objects.all().order_by("id") + version_data = { + version_object.id: data + for version_object, data in zip( + version_objects, + VersionSummarySerializer( + version_objects, many=True, context=self.context + ).data, + ) + } # all encounters associated with location area all_encounters = Encounter.objects.filter(location_area=obj).order_by("pokemon") @@ -1219,7 +1225,7 @@ def get_encounters(self, obj): # each pokemon has multiple versions it could be encountered in for ver in poke_encounters.values("version").distinct(): version_detail = OrderedDict() - version_detail["version"] = version_data[ver["version"] - 1] + version_detail["version"] = version_data[ver["version"]] version_detail["max_chance"] = 0 version_detail["encounter_details"] = [] diff --git a/pokemon_v2/tests.py b/pokemon_v2/tests.py index 2260e6df4..23c2ae95b 100644 --- a/pokemon_v2/tests.py +++ b/pokemon_v2/tests.py @@ -3298,6 +3298,42 @@ def test_location_area_api(self): ), ) + def test_location_area_encounters_with_non_contiguous_version_ids(self): + # Regression test: get_encounters used to look up Version + # summaries by list position (id - 1), assuming ids were a + # contiguous 1-indexed sequence. Deleting a row (or otherwise + # creating a gap) breaks that assumption and returns the wrong + # version, or raises an IndexError. + location_area = self.setup_location_area_data(name="lctn area for id gap test") + + # Create and delete a version so that the id actually used + # below is not contiguous starting from 1. + doomed_version = self.setup_version_data(name="doomed ver") + doomed_version.delete() + + version = self.setup_version_data(name="ver after gap") + pokemon = self.setup_pokemon_data(name="pkmn for id gap test") + encounter_slot = self.setup_encounter_slot_data(rarity=30) + encounter = self.setup_encounter_data( + location_area=location_area, + encounter_slot=encounter_slot, + pokemon=pokemon, + version=version, + ) + + response = self.client.get( + "{}/location-area/{}/".format(API_V2, location_area.pk) + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + version_detail = response.data["pokemon_encounters"][0]["version_details"][0] + self.assertEqual(version_detail["version"]["name"], version.name) + self.assertEqual( + version_detail["version"]["url"], + "{}{}/version/{}/".format(TEST_HOST, API_V2, encounter.version.pk), + ) + # Contest Tests def test_contest_type_api(self): contest_type = self.setup_contest_type_data(name="base cntst tp")