Stardew Valley: Cut tests by 3 minutes (#2375)

* Stardew Valley: Test: unify mods

* Stardew Valley: Test: don't use SVTestBase where setUp is unused

* Stardew Valley: Test: remove duplicate backpack test

* Stardew Valley: Test: remove 2,3,4 heart tests

assume the math is correct with just 2 points on the curve

* Stardew Valley: Test: reduce duplicate test/gen runs

* Stardew Valley: Test: Change 'long' tests to not use TestBase

TestBase' setUp is not being used in the changed TestCases

* Stardew Valley: Test: Use subtests and inheritance for backpacks

* Stardew Valley: Test: add flag to skip some of the extensive tests by default
This commit is contained in:
black-sliver 2023-10-28 00:18:33 +02:00 committed by GitHub
parent c470849cee
commit e3112e5d51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 200 additions and 195 deletions

View File

@ -21,3 +21,11 @@ class ModNames:
ayeisha = "Ayeisha - The Postal Worker (Custom NPC)" ayeisha = "Ayeisha - The Postal Worker (Custom NPC)"
riley = "Custom NPC - Riley" riley = "Custom NPC - Riley"
skull_cavern_elevator = "Skull Cavern Elevator" skull_cavern_elevator = "Skull Cavern Elevator"
all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack,
ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology,
ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna,
ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene,
ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores,
ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator})

View File

@ -5,40 +5,41 @@ from .. import options
class TestBackpackVanilla(SVTestBase): class TestBackpackVanilla(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla} options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla}
def test_no_backpack_in_pool(self): def test_no_backpack(self):
item_names = {item.name for item in self.multiworld.get_items()} with self.subTest("no items"):
self.assertNotIn("Progressive Backpack", item_names) item_names = {item.name for item in self.multiworld.get_items()}
self.assertNotIn("Progressive Backpack", item_names)
def test_no_backpack_locations(self): with self.subTest("no locations"):
location_names = {location.name for location in self.multiworld.get_locations()} location_names = {location.name for location in self.multiworld.get_locations()}
self.assertNotIn("Large Pack", location_names) self.assertNotIn("Large Pack", location_names)
self.assertNotIn("Deluxe Pack", location_names) self.assertNotIn("Deluxe Pack", location_names)
class TestBackpackProgressive(SVTestBase): class TestBackpackProgressive(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive} options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive}
def test_backpack_is_in_pool_2_times(self): def test_backpack(self):
item_names = [item.name for item in self.multiworld.get_items()] with self.subTest(check="has items"):
self.assertEqual(item_names.count("Progressive Backpack"), 2) item_names = [item.name for item in self.multiworld.get_items()]
self.assertEqual(item_names.count("Progressive Backpack"), 2)
def test_2_backpack_locations(self): with self.subTest(check="has locations"):
location_names = {location.name for location in self.multiworld.get_locations()} location_names = {location.name for location in self.multiworld.get_locations()}
self.assertIn("Large Pack", location_names) self.assertIn("Large Pack", location_names)
self.assertIn("Deluxe Pack", location_names) self.assertIn("Deluxe Pack", location_names)
class TestBackpackEarlyProgressive(SVTestBase): class TestBackpackEarlyProgressive(TestBackpackProgressive):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive} options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive}
def test_backpack_is_in_pool_2_times(self): @property
item_names = [item.name for item in self.multiworld.get_items()] def run_default_tests(self) -> bool:
self.assertEqual(item_names.count("Progressive Backpack"), 2) # EarlyProgressive is default
return False
def test_2_backpack_locations(self): def test_backpack(self):
location_names = {location.name for location in self.multiworld.get_locations()} super().test_backpack()
self.assertIn("Large Pack", location_names)
self.assertIn("Deluxe Pack", location_names)
def test_progressive_backpack_is_in_early_pool(self): with self.subTest(check="is early"):
self.assertIn("Progressive Backpack", self.multiworld.early_items[1]) self.assertIn("Progressive Backpack", self.multiworld.early_items[1])

View File

@ -1,5 +1,8 @@
import typing
from BaseClasses import ItemClassification, MultiWorld from BaseClasses import ItemClassification, MultiWorld
from . import setup_solo_multiworld, SVTestBase from . import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_with_mods, \
allsanity_options_without_mods, minimal_locations_maximal_items
from .. import locations, items, location_table, options from .. import locations, items, location_table, options
from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name
from ..items import items_by_group, Group from ..items import items_by_group, Group
@ -7,11 +10,11 @@ from ..locations import LocationTags
from ..mods.mod_data import ModNames from ..mods.mod_data import ModNames
def get_real_locations(tester: SVTestBase, multiworld: MultiWorld): def get_real_locations(tester: typing.Union[SVTestBase, SVTestCase], multiworld: MultiWorld):
return [location for location in multiworld.get_locations(tester.player) if not location.event] return [location for location in multiworld.get_locations(tester.player) if not location.event]
def get_real_location_names(tester: SVTestBase, multiworld: MultiWorld): def get_real_location_names(tester: typing.Union[SVTestBase, SVTestCase], multiworld: MultiWorld):
return [location.name for location in multiworld.get_locations(tester.player) if not location.event] return [location.name for location in multiworld.get_locations(tester.player) if not location.event]
@ -115,21 +118,6 @@ class TestNoGingerIslandItemGeneration(SVTestBase):
self.assertTrue(count == 0 or count == 2) self.assertTrue(count == 0 or count == 2)
class TestGivenProgressiveBackpack(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive}
def test_when_generate_world_then_two_progressive_backpack_are_added(self):
self.assertEqual(self.multiworld.itempool.count(self.world.create_item("Progressive Backpack")), 2)
def test_when_generate_world_then_backpack_locations_are_added(self):
created_locations = {location.name for location in self.multiworld.get_locations(1)}
backpacks_exist = [location.name in created_locations
for location in locations.locations_by_tag[LocationTags.BACKPACK]
if location.name != "Premium Pack"]
all_exist = all(backpacks_exist)
self.assertTrue(all_exist)
class TestRemixedMineRewards(SVTestBase): class TestRemixedMineRewards(SVTestBase):
def test_when_generate_world_then_one_reward_is_added_per_chest(self): def test_when_generate_world_then_one_reward_is_added_per_chest(self):
# assert self.world.create_item("Rusty Sword") in self.multiworld.itempool # assert self.world.create_item("Rusty Sword") in self.multiworld.itempool
@ -205,17 +193,17 @@ class TestLocationGeneration(SVTestBase):
self.assertIn(location.name, location_table) self.assertIn(location.name, location_table)
class TestLocationAndItemCount(SVTestBase): class TestLocationAndItemCount(SVTestCase):
def test_minimal_location_maximal_items_still_valid(self): def test_minimal_location_maximal_items_still_valid(self):
min_max_options = self.minimal_locations_maximal_items() min_max_options = minimal_locations_maximal_items()
multiworld = setup_solo_multiworld(min_max_options) multiworld = setup_solo_multiworld(min_max_options)
valid_locations = get_real_locations(self, multiworld) valid_locations = get_real_locations(self, multiworld)
self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool)) self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool))
def test_allsanity_without_mods_has_at_least_locations(self): def test_allsanity_without_mods_has_at_least_locations(self):
expected_locations = 994 expected_locations = 994
allsanity_options = self.allsanity_options_without_mods() allsanity_options = allsanity_options_without_mods()
multiworld = setup_solo_multiworld(allsanity_options) multiworld = setup_solo_multiworld(allsanity_options)
number_locations = len(get_real_locations(self, multiworld)) number_locations = len(get_real_locations(self, multiworld))
self.assertGreaterEqual(number_locations, expected_locations) self.assertGreaterEqual(number_locations, expected_locations)
@ -228,7 +216,7 @@ class TestLocationAndItemCount(SVTestBase):
def test_allsanity_with_mods_has_at_least_locations(self): def test_allsanity_with_mods_has_at_least_locations(self):
expected_locations = 1246 expected_locations = 1246
allsanity_options = self.allsanity_options_with_mods() allsanity_options = allsanity_options_with_mods()
multiworld = setup_solo_multiworld(allsanity_options) multiworld = setup_solo_multiworld(allsanity_options)
number_locations = len(get_real_locations(self, multiworld)) number_locations = len(get_real_locations(self, multiworld))
self.assertGreaterEqual(number_locations, expected_locations) self.assertGreaterEqual(number_locations, expected_locations)
@ -245,6 +233,11 @@ class TestFriendsanityNone(SVTestBase):
options.Friendsanity.internal_name: options.Friendsanity.option_none, options.Friendsanity.internal_name: options.Friendsanity.option_none,
} }
@property
def run_default_tests(self) -> bool:
# None is default
return False
def test_no_friendsanity_items(self): def test_no_friendsanity_items(self):
for item in self.multiworld.itempool: for item in self.multiworld.itempool:
self.assertFalse(item.name.endswith(" <3")) self.assertFalse(item.name.endswith(" <3"))
@ -416,6 +409,7 @@ class TestFriendsanityAllNpcsWithMarriage(SVTestBase):
self.assertLessEqual(int(hearts), 10) self.assertLessEqual(int(hearts), 10)
""" # Assuming math is correct if we check 2 points
class TestFriendsanityAllNpcsWithMarriageHeartSize2(SVTestBase): class TestFriendsanityAllNpcsWithMarriageHeartSize2(SVTestBase):
options = { options = {
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
@ -528,6 +522,7 @@ class TestFriendsanityAllNpcsWithMarriageHeartSize4(SVTestBase):
self.assertTrue(hearts == 4 or hearts == 8 or hearts == 12 or hearts == 14) self.assertTrue(hearts == 4 or hearts == 8 or hearts == 12 or hearts == 14)
else: else:
self.assertTrue(hearts == 4 or hearts == 8 or hearts == 10) self.assertTrue(hearts == 4 or hearts == 8 or hearts == 10)
"""
class TestFriendsanityAllNpcsWithMarriageHeartSize5(SVTestBase): class TestFriendsanityAllNpcsWithMarriageHeartSize5(SVTestBase):

View File

@ -6,12 +6,12 @@ import random
from typing import Set from typing import Set
from BaseClasses import ItemClassification, MultiWorld from BaseClasses import ItemClassification, MultiWorld
from . import setup_solo_multiworld, SVTestBase from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods
from .. import ItemData, StardewValleyWorld from .. import ItemData, StardewValleyWorld
from ..items import Group, item_table from ..items import Group, item_table
class TestItems(SVTestBase): class TestItems(SVTestCase):
def test_can_create_item_of_resource_pack(self): def test_can_create_item_of_resource_pack(self):
item_name = "Resource Pack: 500 Money" item_name = "Resource Pack: 500 Money"
@ -46,7 +46,7 @@ class TestItems(SVTestBase):
def test_correct_number_of_stardrops(self): def test_correct_number_of_stardrops(self):
seed = random.randrange(sys.maxsize) seed = random.randrange(sys.maxsize)
allsanity_options = self.allsanity_options_without_mods() allsanity_options = allsanity_options_without_mods()
multiworld = setup_solo_multiworld(allsanity_options, seed=seed) multiworld = setup_solo_multiworld(allsanity_options, seed=seed)
stardrop_items = [item for item in multiworld.get_items() if "Stardrop" in item.name] stardrop_items = [item for item in multiworld.get_items() if "Stardrop" in item.name]
self.assertEqual(len(stardrop_items), 5) self.assertEqual(len(stardrop_items), 5)

View File

@ -1,10 +1,11 @@
import itertools import itertools
import unittest
from random import random from random import random
from typing import Dict from typing import Dict
from BaseClasses import ItemClassification, MultiWorld from BaseClasses import ItemClassification, MultiWorld
from Options import SpecialRange from Options import SpecialRange
from . import setup_solo_multiworld, SVTestBase from . import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods
from .. import StardewItem, items_by_group, Group, StardewValleyWorld from .. import StardewItem, items_by_group, Group, StardewValleyWorld
from ..locations import locations_by_tag, LocationTags, location_table from ..locations import locations_by_tag, LocationTags, location_table
from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations
@ -17,21 +18,21 @@ SEASONS = {Season.spring, Season.summer, Season.fall, Season.winter}
TOOLS = {"Hoe", "Pickaxe", "Axe", "Watering Can", "Trash Can", "Fishing Rod"} TOOLS = {"Hoe", "Pickaxe", "Axe", "Watering Can", "Trash Can", "Fishing Rod"}
def assert_can_win(tester: SVTestBase, multiworld: MultiWorld): def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld):
for item in multiworld.get_items(): for item in multiworld.get_items():
multiworld.state.collect(item) multiworld.state.collect(item)
tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state)) tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state))
def basic_checks(tester: SVTestBase, multiworld: MultiWorld): def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld):
tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items()) tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items())
assert_can_win(tester, multiworld) assert_can_win(tester, multiworld)
non_event_locations = [location for location in multiworld.get_locations() if not location.event] non_event_locations = [location for location in multiworld.get_locations() if not location.event]
tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) tester.assertEqual(len(multiworld.itempool), len(non_event_locations))
def check_no_ginger_island(tester: SVTestBase, multiworld: MultiWorld): def check_no_ginger_island(tester: unittest.TestCase, multiworld: MultiWorld):
ginger_island_items = [item_data.name for item_data in items_by_group[Group.GINGER_ISLAND]] ginger_island_items = [item_data.name for item_data in items_by_group[Group.GINGER_ISLAND]]
ginger_island_locations = [location_data.name for location_data in locations_by_tag[LocationTags.GINGER_ISLAND]] ginger_island_locations = [location_data.name for location_data in locations_by_tag[LocationTags.GINGER_ISLAND]]
for item in multiworld.get_items(): for item in multiworld.get_items():
@ -48,9 +49,9 @@ def get_option_choices(option) -> Dict[str, int]:
return {} return {}
class TestGenerateDynamicOptions(SVTestBase): class TestGenerateDynamicOptions(SVTestCase):
def test_given_special_range_when_generate_then_basic_checks(self): def test_given_special_range_when_generate_then_basic_checks(self):
options = self.world.options_dataclass.type_hints options = StardewValleyWorld.options_dataclass.type_hints
for option_name, option in options.items(): for option_name, option in options.items():
if not isinstance(option, SpecialRange): if not isinstance(option, SpecialRange):
continue continue
@ -62,7 +63,7 @@ class TestGenerateDynamicOptions(SVTestBase):
def test_given_choice_when_generate_then_basic_checks(self): def test_given_choice_when_generate_then_basic_checks(self):
seed = int(random() * pow(10, 18) - 1) seed = int(random() * pow(10, 18) - 1)
options = self.world.options_dataclass.type_hints options = StardewValleyWorld.options_dataclass.type_hints
for option_name, option in options.items(): for option_name, option in options.items():
if not option.options: if not option.options:
continue continue
@ -73,7 +74,7 @@ class TestGenerateDynamicOptions(SVTestBase):
basic_checks(self, multiworld) basic_checks(self, multiworld)
class TestGoal(SVTestBase): class TestGoal(SVTestCase):
def test_given_goal_when_generate_then_victory_is_in_correct_location(self): def test_given_goal_when_generate_then_victory_is_in_correct_location(self):
for goal, location in [("community_center", GoalName.community_center), for goal, location in [("community_center", GoalName.community_center),
("grandpa_evaluation", GoalName.grandpa_evaluation), ("grandpa_evaluation", GoalName.grandpa_evaluation),
@ -90,7 +91,7 @@ class TestGoal(SVTestBase):
self.assertEqual(victory.name, location) self.assertEqual(victory.name, location)
class TestSeasonRandomization(SVTestBase): class TestSeasonRandomization(SVTestCase):
def test_given_disabled_when_generate_then_all_seasons_are_precollected(self): def test_given_disabled_when_generate_then_all_seasons_are_precollected(self):
world_options = {SeasonRandomization.internal_name: SeasonRandomization.option_disabled} world_options = {SeasonRandomization.internal_name: SeasonRandomization.option_disabled}
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)
@ -114,7 +115,7 @@ class TestSeasonRandomization(SVTestBase):
self.assertEqual(items.count(Season.progressive), 3) self.assertEqual(items.count(Season.progressive), 3)
class TestToolProgression(SVTestBase): class TestToolProgression(SVTestCase):
def test_given_vanilla_when_generate_then_no_tool_in_pool(self): def test_given_vanilla_when_generate_then_no_tool_in_pool(self):
world_options = {ToolProgression.internal_name: ToolProgression.option_vanilla} world_options = {ToolProgression.internal_name: ToolProgression.option_vanilla}
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)
@ -147,9 +148,9 @@ class TestToolProgression(SVTestBase):
self.assertIn("Purchase Iridium Rod", locations) self.assertIn("Purchase Iridium Rod", locations)
class TestGenerateAllOptionsWithExcludeGingerIsland(SVTestBase): class TestGenerateAllOptionsWithExcludeGingerIsland(SVTestCase):
def test_given_special_range_when_generate_exclude_ginger_island(self): def test_given_special_range_when_generate_exclude_ginger_island(self):
options = self.world.options_dataclass.type_hints options = StardewValleyWorld.options_dataclass.type_hints
for option_name, option in options.items(): for option_name, option in options.items():
if not isinstance(option, SpecialRange) or option_name == ExcludeGingerIsland.internal_name: if not isinstance(option, SpecialRange) or option_name == ExcludeGingerIsland.internal_name:
continue continue
@ -162,7 +163,7 @@ class TestGenerateAllOptionsWithExcludeGingerIsland(SVTestBase):
def test_given_choice_when_generate_exclude_ginger_island(self): def test_given_choice_when_generate_exclude_ginger_island(self):
seed = int(random() * pow(10, 18) - 1) seed = int(random() * pow(10, 18) - 1)
options = self.world.options_dataclass.type_hints options = StardewValleyWorld.options_dataclass.type_hints
for option_name, option in options.items(): for option_name, option in options.items():
if not option.options or option_name == ExcludeGingerIsland.internal_name: if not option.options or option_name == ExcludeGingerIsland.internal_name:
continue continue
@ -191,9 +192,9 @@ class TestGenerateAllOptionsWithExcludeGingerIsland(SVTestBase):
basic_checks(self, multiworld) basic_checks(self, multiworld)
class TestTraps(SVTestBase): class TestTraps(SVTestCase):
def test_given_no_traps_when_generate_then_no_trap_in_pool(self): def test_given_no_traps_when_generate_then_no_trap_in_pool(self):
world_options = self.allsanity_options_without_mods() world_options = allsanity_options_without_mods()
world_options.update({TrapItems.internal_name: TrapItems.option_no_traps}) world_options.update({TrapItems.internal_name: TrapItems.option_no_traps})
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)
@ -209,7 +210,7 @@ class TestTraps(SVTestBase):
for value in trap_option.options: for value in trap_option.options:
if value == "no_traps": if value == "no_traps":
continue continue
world_options = self.allsanity_options_with_mods() world_options = allsanity_options_with_mods()
world_options.update({TrapItems.internal_name: trap_option.options[value]}) world_options.update({TrapItems.internal_name: trap_option.options[value]})
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)
trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups and item_data.mod_name is None] trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups and item_data.mod_name is None]
@ -219,7 +220,7 @@ class TestTraps(SVTestBase):
self.assertIn(item, multiworld_items) self.assertIn(item, multiworld_items)
class TestSpecialOrders(SVTestBase): class TestSpecialOrders(SVTestCase):
def test_given_disabled_then_no_order_in_pool(self): def test_given_disabled_then_no_order_in_pool(self):
world_options = {SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled} world_options = {SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled}
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)

View File

@ -2,7 +2,7 @@ import random
import sys import sys
import unittest import unittest
from . import SVTestBase, setup_solo_multiworld from . import SVTestCase, setup_solo_multiworld
from .. import options, StardewValleyWorld, StardewValleyOptions from .. import options, StardewValleyWorld, StardewValleyOptions
from ..options import EntranceRandomization, ExcludeGingerIsland from ..options import EntranceRandomization, ExcludeGingerIsland
from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag
@ -88,7 +88,7 @@ class TestEntranceRando(unittest.TestCase):
f"Connections are duplicated in randomization. Seed = {seed}") f"Connections are duplicated in randomization. Seed = {seed}")
class TestEntranceClassifications(SVTestBase): class TestEntranceClassifications(SVTestCase):
def test_non_progression_are_all_accessible_with_empty_inventory(self): def test_non_progression_are_all_accessible_with_empty_inventory(self):
for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),

View File

@ -1,8 +1,10 @@
import os import os
import unittest
from argparse import Namespace from argparse import Namespace
from typing import Dict, FrozenSet, Tuple, Any, ClassVar from typing import Dict, FrozenSet, Tuple, Any, ClassVar
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Utils import cache_argsless
from test.TestBase import WorldTestBase from test.TestBase import WorldTestBase
from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld
from .. import StardewValleyWorld from .. import StardewValleyWorld
@ -13,11 +15,17 @@ from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Frien
BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods
class SVTestBase(WorldTestBase): class SVTestCase(unittest.TestCase):
player: ClassVar[int] = 1
"""Set to False to not skip some 'extra' tests"""
skip_extra_tests: bool = True
"""Set to False to run tests that take long"""
skip_long_tests: bool = True
class SVTestBase(WorldTestBase, SVTestCase):
game = "Stardew Valley" game = "Stardew Valley"
world: StardewValleyWorld world: StardewValleyWorld
player: ClassVar[int] = 1
skip_long_tests: bool = True
def world_setup(self, *args, **kwargs): def world_setup(self, *args, **kwargs):
super().world_setup(*args, **kwargs) super().world_setup(*args, **kwargs)
@ -34,66 +42,73 @@ class SVTestBase(WorldTestBase):
should_run_default_tests = is_not_stardew_test and super().run_default_tests should_run_default_tests = is_not_stardew_test and super().run_default_tests
return should_run_default_tests return should_run_default_tests
def minimal_locations_maximal_items(self):
min_max_options = {
SeasonRandomization.internal_name: SeasonRandomization.option_randomized,
Cropsanity.internal_name: Cropsanity.option_shuffled,
BackpackProgression.internal_name: BackpackProgression.option_vanilla,
ToolProgression.internal_name: ToolProgression.option_vanilla,
SkillProgression.internal_name: SkillProgression.option_vanilla,
BuildingProgression.internal_name: BuildingProgression.option_vanilla,
ElevatorProgression.internal_name: ElevatorProgression.option_vanilla,
ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled,
SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled,
HelpWantedLocations.internal_name: 0,
Fishsanity.internal_name: Fishsanity.option_none,
Museumsanity.internal_name: Museumsanity.option_none,
Friendsanity.internal_name: Friendsanity.option_none,
NumberOfMovementBuffs.internal_name: 12,
NumberOfLuckBuffs.internal_name: 12,
}
return min_max_options
def allsanity_options_without_mods(self): @cache_argsless
allsanity = { def minimal_locations_maximal_items():
Goal.internal_name: Goal.option_perfection, min_max_options = {
BundleRandomization.internal_name: BundleRandomization.option_shuffled, SeasonRandomization.internal_name: SeasonRandomization.option_randomized,
BundlePrice.internal_name: BundlePrice.option_expensive, Cropsanity.internal_name: Cropsanity.option_shuffled,
SeasonRandomization.internal_name: SeasonRandomization.option_randomized, BackpackProgression.internal_name: BackpackProgression.option_vanilla,
Cropsanity.internal_name: Cropsanity.option_shuffled, ToolProgression.internal_name: ToolProgression.option_vanilla,
BackpackProgression.internal_name: BackpackProgression.option_progressive, SkillProgression.internal_name: SkillProgression.option_vanilla,
ToolProgression.internal_name: ToolProgression.option_progressive, BuildingProgression.internal_name: BuildingProgression.option_vanilla,
SkillProgression.internal_name: SkillProgression.option_progressive, ElevatorProgression.internal_name: ElevatorProgression.option_vanilla,
BuildingProgression.internal_name: BuildingProgression.option_progressive, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled,
FestivalLocations.internal_name: FestivalLocations.option_hard, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled,
ElevatorProgression.internal_name: ElevatorProgression.option_progressive, HelpWantedLocations.internal_name: 0,
ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, Fishsanity.internal_name: Fishsanity.option_none,
SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, Museumsanity.internal_name: Museumsanity.option_none,
HelpWantedLocations.internal_name: 56, Friendsanity.internal_name: Friendsanity.option_none,
Fishsanity.internal_name: Fishsanity.option_all, NumberOfMovementBuffs.internal_name: 12,
Museumsanity.internal_name: Museumsanity.option_all, NumberOfLuckBuffs.internal_name: 12,
Friendsanity.internal_name: Friendsanity.option_all_with_marriage, }
FriendsanityHeartSize.internal_name: 1, return min_max_options
NumberOfMovementBuffs.internal_name: 12,
NumberOfLuckBuffs.internal_name: 12,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, @cache_argsless
TrapItems.internal_name: TrapItems.option_nightmare, def allsanity_options_without_mods():
} allsanity = {
return allsanity Goal.internal_name: Goal.option_perfection,
BundleRandomization.internal_name: BundleRandomization.option_shuffled,
BundlePrice.internal_name: BundlePrice.option_expensive,
SeasonRandomization.internal_name: SeasonRandomization.option_randomized,
Cropsanity.internal_name: Cropsanity.option_shuffled,
BackpackProgression.internal_name: BackpackProgression.option_progressive,
ToolProgression.internal_name: ToolProgression.option_progressive,
SkillProgression.internal_name: SkillProgression.option_progressive,
BuildingProgression.internal_name: BuildingProgression.option_progressive,
FestivalLocations.internal_name: FestivalLocations.option_hard,
ElevatorProgression.internal_name: ElevatorProgression.option_progressive,
ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling,
SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi,
HelpWantedLocations.internal_name: 56,
Fishsanity.internal_name: Fishsanity.option_all,
Museumsanity.internal_name: Museumsanity.option_all,
Friendsanity.internal_name: Friendsanity.option_all_with_marriage,
FriendsanityHeartSize.internal_name: 1,
NumberOfMovementBuffs.internal_name: 12,
NumberOfLuckBuffs.internal_name: 12,
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false,
TrapItems.internal_name: TrapItems.option_nightmare,
}
return allsanity
@cache_argsless
def allsanity_options_with_mods():
allsanity = {}
allsanity.update(allsanity_options_without_mods())
all_mods = (
ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack,
ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology,
ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna,
ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene,
ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores,
ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator
)
allsanity.update({Mods.internal_name: all_mods})
return allsanity
def allsanity_options_with_mods(self):
allsanity = {}
allsanity.update(self.allsanity_options_without_mods())
all_mods = (
ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack,
ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology,
ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna,
ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene,
ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores,
ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator
)
allsanity.update({Mods.internal_name: all_mods})
return allsanity
pre_generated_worlds = {} pre_generated_worlds = {}

View File

@ -1,8 +1,8 @@
import unittest
from typing import List from typing import List
from BaseClasses import MultiWorld, ItemClassification from BaseClasses import MultiWorld, ItemClassification
from ... import StardewItem from ... import StardewItem
from .. import SVTestBase
def get_all_item_names(multiworld: MultiWorld) -> List[str]: def get_all_item_names(multiworld: MultiWorld) -> List[str]:
@ -13,21 +13,21 @@ def get_all_location_names(multiworld: MultiWorld) -> List[str]:
return [location.name for location in multiworld.get_locations() if not location.event] return [location.name for location in multiworld.get_locations() if not location.event]
def assert_victory_exists(tester: SVTestBase, multiworld: MultiWorld): def assert_victory_exists(tester: unittest.TestCase, multiworld: MultiWorld):
tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items()) tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items())
def collect_all_then_assert_can_win(tester: SVTestBase, multiworld: MultiWorld): def collect_all_then_assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld):
for item in multiworld.get_items(): for item in multiworld.get_items():
multiworld.state.collect(item) multiworld.state.collect(item)
tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state)) tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state))
def assert_can_win(tester: SVTestBase, multiworld: MultiWorld): def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld):
assert_victory_exists(tester, multiworld) assert_victory_exists(tester, multiworld)
collect_all_then_assert_can_win(tester, multiworld) collect_all_then_assert_can_win(tester, multiworld)
def assert_same_number_items_locations(tester: SVTestBase, multiworld: MultiWorld): def assert_same_number_items_locations(tester: unittest.TestCase, multiworld: MultiWorld):
non_event_locations = [location for location in multiworld.get_locations() if not location.event] non_event_locations = [location for location in multiworld.get_locations() if not location.event]
tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) tester.assertEqual(len(multiworld.itempool), len(non_event_locations))

View File

@ -1,23 +1,17 @@
import unittest
from typing import List, Union from typing import List, Union
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from worlds.stardew_valley.mods.mod_data import ModNames from worlds.stardew_valley.mods.mod_data import all_mods
from worlds.stardew_valley.test import setup_solo_multiworld from worlds.stardew_valley.test import setup_solo_multiworld
from worlds.stardew_valley.test.TestOptions import basic_checks, SVTestBase from worlds.stardew_valley.test.TestOptions import basic_checks, SVTestCase
from worlds.stardew_valley.items import item_table from worlds.stardew_valley.items import item_table
from worlds.stardew_valley.locations import location_table from worlds.stardew_valley.locations import location_table
from worlds.stardew_valley.options import Mods from worlds.stardew_valley.options import Mods
from .option_names import options_to_include from .option_names import options_to_include
all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack,
ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology,
ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna,
ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene,
ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores,
ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator})
def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld):
def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: SVTestBase, multiworld: MultiWorld):
if isinstance(chosen_mods, str): if isinstance(chosen_mods, str):
chosen_mods = [chosen_mods] chosen_mods = [chosen_mods]
for multiworld_item in multiworld.get_items(): for multiworld_item in multiworld.get_items():
@ -30,7 +24,7 @@ def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: SVTestBase
tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods) tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods)
class TestGenerateModsOptions(SVTestBase): class TestGenerateModsOptions(SVTestCase):
def test_given_mod_pairs_when_generate_then_basic_checks(self): def test_given_mod_pairs_when_generate_then_basic_checks(self):
if self.skip_long_tests: if self.skip_long_tests:

View File

@ -1,13 +1,14 @@
import unittest
from typing import Dict from typing import Dict
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Options import SpecialRange from Options import SpecialRange
from .option_names import options_to_include from .option_names import options_to_include
from worlds.stardew_valley.test.checks.world_checks import assert_can_win, assert_same_number_items_locations from worlds.stardew_valley.test.checks.world_checks import assert_can_win, assert_same_number_items_locations
from .. import setup_solo_multiworld, SVTestBase from .. import setup_solo_multiworld, SVTestCase
def basic_checks(tester: SVTestBase, multiworld: MultiWorld): def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld):
assert_can_win(tester, multiworld) assert_can_win(tester, multiworld)
assert_same_number_items_locations(tester, multiworld) assert_same_number_items_locations(tester, multiworld)
@ -20,7 +21,7 @@ def get_option_choices(option) -> Dict[str, int]:
return {} return {}
class TestGenerateDynamicOptions(SVTestBase): class TestGenerateDynamicOptions(SVTestCase):
def test_given_option_pair_when_generate_then_basic_checks(self): def test_given_option_pair_when_generate_then_basic_checks(self):
if self.skip_long_tests: if self.skip_long_tests:
return return

View File

@ -4,7 +4,7 @@ import random
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Options import SpecialRange, Range from Options import SpecialRange, Range
from .option_names import options_to_include from .option_names import options_to_include
from .. import setup_solo_multiworld, SVTestBase from .. import setup_solo_multiworld, SVTestCase
from ..checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid from ..checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid
from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \
assert_festivals_give_access_to_deluxe_scarecrow assert_festivals_give_access_to_deluxe_scarecrow
@ -72,14 +72,14 @@ def generate_many_worlds(number_worlds: int, start_index: int) -> Dict[int, Mult
return multiworlds return multiworlds
def check_every_multiworld_is_valid(tester: SVTestBase, multiworlds: Dict[int, MultiWorld]): def check_every_multiworld_is_valid(tester: SVTestCase, multiworlds: Dict[int, MultiWorld]):
for multiworld_id in multiworlds: for multiworld_id in multiworlds:
multiworld = multiworlds[multiworld_id] multiworld = multiworlds[multiworld_id]
with tester.subTest(f"Checking validity of world {multiworld_id}"): with tester.subTest(f"Checking validity of world {multiworld_id}"):
check_multiworld_is_valid(tester, multiworld_id, multiworld) check_multiworld_is_valid(tester, multiworld_id, multiworld)
def check_multiworld_is_valid(tester: SVTestBase, multiworld_id: int, multiworld: MultiWorld): def check_multiworld_is_valid(tester: SVTestCase, multiworld_id: int, multiworld: MultiWorld):
assert_victory_exists(tester, multiworld) assert_victory_exists(tester, multiworld)
assert_same_number_items_locations(tester, multiworld) assert_same_number_items_locations(tester, multiworld)
assert_goal_world_is_valid(tester, multiworld) assert_goal_world_is_valid(tester, multiworld)
@ -88,7 +88,7 @@ def check_multiworld_is_valid(tester: SVTestBase, multiworld_id: int, multiworld
assert_festivals_give_access_to_deluxe_scarecrow(tester, multiworld) assert_festivals_give_access_to_deluxe_scarecrow(tester, multiworld)
class TestGenerateManyWorlds(SVTestBase): class TestGenerateManyWorlds(SVTestCase):
def test_generate_many_worlds_then_check_results(self): def test_generate_many_worlds_then_check_results(self):
if self.skip_long_tests: if self.skip_long_tests:
return return

View File

@ -7,45 +7,40 @@ class TestBiggerBackpackVanilla(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla, options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla,
options.Mods.internal_name: ModNames.big_backpack} options.Mods.internal_name: ModNames.big_backpack}
def test_no_backpack_in_pool(self): def test_no_backpack(self):
item_names = {item.name for item in self.multiworld.get_items()} with self.subTest(check="no items"):
self.assertNotIn("Progressive Backpack", item_names) item_names = {item.name for item in self.multiworld.get_items()}
self.assertNotIn("Progressive Backpack", item_names)
def test_no_backpack_locations(self): with self.subTest(check="no locations"):
location_names = {location.name for location in self.multiworld.get_locations()} location_names = {location.name for location in self.multiworld.get_locations()}
self.assertNotIn("Large Pack", location_names) self.assertNotIn("Large Pack", location_names)
self.assertNotIn("Deluxe Pack", location_names) self.assertNotIn("Deluxe Pack", location_names)
self.assertNotIn("Premium Pack", location_names) self.assertNotIn("Premium Pack", location_names)
class TestBiggerBackpackProgressive(SVTestBase): class TestBiggerBackpackProgressive(SVTestBase):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive, options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive,
options.Mods.internal_name: ModNames.big_backpack} options.Mods.internal_name: ModNames.big_backpack}
def test_backpack_is_in_pool_3_times(self): def test_backpack(self):
item_names = [item.name for item in self.multiworld.get_items()] with self.subTest(check="has items"):
self.assertEqual(item_names.count("Progressive Backpack"), 3) item_names = [item.name for item in self.multiworld.get_items()]
self.assertEqual(item_names.count("Progressive Backpack"), 3)
def test_3_backpack_locations(self): with self.subTest(check="has locations"):
location_names = {location.name for location in self.multiworld.get_locations()} location_names = {location.name for location in self.multiworld.get_locations()}
self.assertIn("Large Pack", location_names) self.assertIn("Large Pack", location_names)
self.assertIn("Deluxe Pack", location_names) self.assertIn("Deluxe Pack", location_names)
self.assertIn("Premium Pack", location_names) self.assertIn("Premium Pack", location_names)
class TestBiggerBackpackEarlyProgressive(SVTestBase): class TestBiggerBackpackEarlyProgressive(TestBiggerBackpackProgressive):
options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive,
options.Mods.internal_name: ModNames.big_backpack} options.Mods.internal_name: ModNames.big_backpack}
def test_backpack_is_in_pool_3_times(self): def test_backpack(self):
item_names = [item.name for item in self.multiworld.get_items()] super().test_backpack()
self.assertEqual(item_names.count("Progressive Backpack"), 3)
def test_3_backpack_locations(self): with self.subTest(check="is early"):
location_names = {location.name for location in self.multiworld.get_locations()} self.assertIn("Progressive Backpack", self.multiworld.early_items[1])
self.assertIn("Large Pack", location_names)
self.assertIn("Deluxe Pack", location_names)
self.assertIn("Premium Pack", location_names)
def test_progressive_backpack_is_in_early_pool(self):
self.assertIn("Progressive Backpack", self.multiworld.early_items[1])

View File

@ -4,24 +4,17 @@ import random
import sys import sys
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from ...mods.mod_data import ModNames from ...mods.mod_data import all_mods
from .. import setup_solo_multiworld from .. import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods
from ..TestOptions import basic_checks, SVTestBase from ..TestOptions import basic_checks
from ... import items, Group, ItemClassification from ... import items, Group, ItemClassification
from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions
from ...items import item_table, items_by_group from ...items import item_table, items_by_group
from ...locations import location_table from ...locations import location_table
from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems
all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack,
ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology,
ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna,
ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene,
ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores,
ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator})
def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld):
def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: SVTestBase, multiworld: MultiWorld):
if isinstance(chosen_mods, str): if isinstance(chosen_mods, str):
chosen_mods = [chosen_mods] chosen_mods = [chosen_mods]
for multiworld_item in multiworld.get_items(): for multiworld_item in multiworld.get_items():
@ -34,7 +27,7 @@ def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: SVTestBase
tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods) tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods)
class TestGenerateModsOptions(SVTestBase): class TestGenerateModsOptions(SVTestCase):
def test_given_single_mods_when_generate_then_basic_checks(self): def test_given_single_mods_when_generate_then_basic_checks(self):
for mod in all_mods: for mod in all_mods:
@ -50,6 +43,8 @@ class TestGenerateModsOptions(SVTestBase):
multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: option, Mods: mod}) multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: option, Mods: mod})
basic_checks(self, multiworld) basic_checks(self, multiworld)
check_stray_mod_items(mod, self, multiworld) check_stray_mod_items(mod, self, multiworld)
if self.skip_extra_tests:
return # assume the rest will work as well
class TestBaseItemGeneration(SVTestBase): class TestBaseItemGeneration(SVTestBase):
@ -103,7 +98,7 @@ class TestNoGingerIslandModItemGeneration(SVTestBase):
self.assertIn(progression_item.name, all_created_items) self.assertIn(progression_item.name, all_created_items)
class TestModEntranceRando(unittest.TestCase): class TestModEntranceRando(SVTestCase):
def test_mod_entrance_randomization(self): def test_mod_entrance_randomization(self):
@ -137,12 +132,12 @@ class TestModEntranceRando(unittest.TestCase):
f"Connections are duplicated in randomization. Seed = {seed}") f"Connections are duplicated in randomization. Seed = {seed}")
class TestModTraps(SVTestBase): class TestModTraps(SVTestCase):
def test_given_traps_when_generate_then_all_traps_in_pool(self): def test_given_traps_when_generate_then_all_traps_in_pool(self):
for value in TrapItems.options: for value in TrapItems.options:
if value == "no_traps": if value == "no_traps":
continue continue
world_options = self.allsanity_options_without_mods() world_options = allsanity_options_without_mods()
world_options.update({TrapItems.internal_name: TrapItems.options[value], Mods: "Magic"}) world_options.update({TrapItems.internal_name: TrapItems.options[value], Mods: "Magic"})
multi_world = setup_solo_multiworld(world_options) multi_world = setup_solo_multiworld(world_options)
trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups] trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups]