2025-05-21 14:30:39 +02:00
|
|
|
from unittest import TestCase
|
|
|
|
|
|
|
|
from test.bases import WorldTestBase
|
2025-07-28 17:01:57 +02:00
|
|
|
from .. import ShapezWorld
|
2025-05-21 14:30:39 +02:00
|
|
|
from ..data.strings import GOALS, OTHER, ITEMS, LOCATIONS, CATEGORY, OPTIONS, SHAPESANITY
|
|
|
|
from ..options import max_levels_and_upgrades, max_shapesanity
|
|
|
|
|
|
|
|
|
|
|
|
class ShapezTestBase(WorldTestBase):
|
|
|
|
game = OTHER.game_name
|
|
|
|
world: ShapezWorld
|
|
|
|
|
|
|
|
def test_location_count(self):
|
|
|
|
self.assertTrue(self.world.location_count > 0,
|
|
|
|
f"location_count is {self.world.location_count} for some reason.")
|
|
|
|
|
|
|
|
def test_logic_lists(self):
|
|
|
|
logic_buildings = [ITEMS.cutter, ITEMS.rotator, ITEMS.painter, ITEMS.color_mixer, ITEMS.stacker]
|
|
|
|
for building in logic_buildings:
|
|
|
|
count = self.world.level_logic.count(building)
|
|
|
|
self.assertTrue(count == 1, f"{building} was found {count} times in level_logic.")
|
|
|
|
count = self.world.upgrade_logic.count(building)
|
|
|
|
self.assertTrue(count == 1, f"{building} was found {count} times in upgrade_logic.")
|
|
|
|
self.assertTrue(len(self.world.level_logic) == 5,
|
|
|
|
f"level_logic contains {len(self.world.level_logic)} entries instead of the expected 5.")
|
|
|
|
self.assertTrue(len(self.world.upgrade_logic) == 5,
|
|
|
|
f"upgrade_logic contains {len(self.world.upgrade_logic)} entries instead of the expected 5.")
|
|
|
|
|
|
|
|
def test_random_logic_phase_length(self):
|
|
|
|
self.assertTrue(len(self.world.random_logic_phase_length) == 5,
|
|
|
|
f"random_logic_phase_length contains {len(self.world.random_logic_phase_length)} entries " +
|
|
|
|
f"instead of the expected 5.")
|
|
|
|
self.assertTrue(sum(self.world.random_logic_phase_length) < self.world.maxlevel,
|
|
|
|
f"The sum of all random phase lengths is greater than allowed: " +
|
|
|
|
str(sum(self.world.random_logic_phase_length)))
|
|
|
|
for length in self.world.random_logic_phase_length:
|
|
|
|
self.assertTrue(length in range(self.world.maxlevel),
|
|
|
|
f"Found an illegal value in random_logic_phase_length: {length}")
|
|
|
|
|
|
|
|
def test_category_random_logic_amounts(self):
|
|
|
|
self.assertTrue(len(self.world.category_random_logic_amounts) == 4,
|
|
|
|
f"Found {len(self.world.category_random_logic_amounts)} instead of 4 keys in "
|
|
|
|
f"category_random_logic_amounts.")
|
|
|
|
self.assertTrue(min(self.world.category_random_logic_amounts.values()) == 0,
|
|
|
|
"Found a value less than or no 0 in category_random_logic_amounts.")
|
|
|
|
self.assertTrue(max(self.world.category_random_logic_amounts.values()) <= 5,
|
|
|
|
"Found a value greater than 5 in category_random_logic_amounts.")
|
|
|
|
|
|
|
|
def test_maxlevel_and_finaltier(self):
|
|
|
|
self.assertTrue(self.world.maxlevel in range(25, max_levels_and_upgrades),
|
|
|
|
f"Found an illegal value for maxlevel: {self.world.maxlevel}")
|
|
|
|
self.assertTrue(self.world.finaltier in range(8, max_levels_and_upgrades+1),
|
|
|
|
f"Found an illegal value for finaltier: {self.world.finaltier}")
|
|
|
|
|
|
|
|
def test_included_locations(self):
|
|
|
|
self.assertTrue(len(self.world.included_locations) > 0, "Found no locations cached in included_locations.")
|
|
|
|
self.assertTrue(LOCATIONS.level(1) in self.world.included_locations.keys(),
|
|
|
|
"Could not find Level 1 (guraranteed location) cached in included_locations.")
|
|
|
|
self.assertTrue(LOCATIONS.upgrade(CATEGORY.belt, "II") in self.world.included_locations.keys(),
|
|
|
|
"Could not find Belt Upgrade Tier II (guraranteed location) cached in included_locations.")
|
|
|
|
self.assertTrue(LOCATIONS.shapesanity(1) in self.world.included_locations.keys(),
|
|
|
|
"Could not find Shapesanity 1 (guraranteed location) cached in included_locations.")
|
|
|
|
|
|
|
|
def test_shapesanity_names(self):
|
|
|
|
names_length = len(self.world.shapesanity_names)
|
|
|
|
locations_length = len([0 for loc in self.multiworld.get_locations(self.player) if "Shapesanity" in loc.name])
|
|
|
|
self.assertEqual(names_length, locations_length,
|
|
|
|
f"The amount of shapesanity names ({names_length}) does not match the amount of included " +
|
|
|
|
f"shapesanity locations ({locations_length}).")
|
|
|
|
self.assertTrue(SHAPESANITY.full(SHAPESANITY.uncolored, SHAPESANITY.circle) in self.world.shapesanity_names,
|
|
|
|
"Uncolored Circle is guaranteed but was not found in shapesanity_names.")
|
|
|
|
|
|
|
|
def test_efficiency_iii_no_softlock(self):
|
|
|
|
if self.world.options.goal == GOALS.efficiency_iii:
|
|
|
|
for item in self.multiworld.itempool:
|
|
|
|
self.assertFalse(item.name.endswith("Upgrade Trap"),
|
|
|
|
"Item pool contains an upgrade trap, which could make the efficiency_iii goal "
|
|
|
|
"unreachable if collected.")
|
|
|
|
|
|
|
|
|
|
|
|
class TestGlobalOptionsImport(TestCase):
|
|
|
|
|
|
|
|
def test_global_options_import(self):
|
|
|
|
self.assertTrue(isinstance(max_levels_and_upgrades, int), f"The global option max_levels_and_upgrades is not " +
|
|
|
|
f"an integer, but instead a " +
|
|
|
|
f"{type(max_levels_and_upgrades)}.")
|
|
|
|
self.assertTrue(max_levels_and_upgrades >= 27, f"max_levels_and_upgrades must be at least 27, but is " +
|
|
|
|
f"{max_levels_and_upgrades} instead.")
|
|
|
|
self.assertTrue(isinstance(max_shapesanity, int), f"The global option max_shapesanity is not an integer, but " +
|
|
|
|
f"instead a {type(max_levels_and_upgrades)}.")
|
|
|
|
self.assertTrue(max_shapesanity >= 4, f"max_shapesanity must be at least 4, but is " +
|
|
|
|
f"{max_levels_and_upgrades} instead.")
|
|
|
|
|
|
|
|
|
2025-06-06 00:05:53 +02:00
|
|
|
# The following unittests are intended to test all code paths of the generator
|
2025-05-21 14:30:39 +02:00
|
|
|
|
|
|
|
class TestAllRelevantOptions1(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.vanilla,
|
|
|
|
"randomize_level_requirements": False,
|
|
|
|
"randomize_upgrade_requirements": False,
|
|
|
|
"complexity_growth_gradient": "0.1234",
|
|
|
|
"early_balancer_tunnel_and_trash": "none",
|
|
|
|
"lock_belt_and_extractor": True,
|
|
|
|
"include_achievements": True,
|
|
|
|
"exclude_softlock_achievements": False,
|
|
|
|
"exclude_long_playtime_achievements": False,
|
|
|
|
"exclude_progression_unreasonable": True,
|
|
|
|
"shapesanity_amount": max_shapesanity,
|
|
|
|
"traps_percentage": "random"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TestAllRelevantOptions2(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.mam,
|
|
|
|
"goal_amount": max_levels_and_upgrades,
|
|
|
|
"randomize_level_requirements": True,
|
|
|
|
"randomize_upgrade_requirements": True,
|
|
|
|
"randomize_level_logic": OPTIONS.logic_random_steps,
|
|
|
|
"randomize_upgrade_logic": OPTIONS.logic_vanilla_like,
|
|
|
|
"complexity_growth_gradient": "2",
|
|
|
|
"early_balancer_tunnel_and_trash": OPTIONS.buildings_5,
|
|
|
|
"lock_belt_and_extractor": False,
|
|
|
|
"include_achievements": True,
|
|
|
|
"exclude_softlock_achievements": False,
|
|
|
|
"exclude_long_playtime_achievements": False,
|
|
|
|
"exclude_progression_unreasonable": False,
|
|
|
|
"shapesanity_amount": 4,
|
|
|
|
"traps_percentage": 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TestAllRelevantOptions3(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.even_fasterer,
|
|
|
|
"goal_amount": max_levels_and_upgrades,
|
|
|
|
"randomize_level_requirements": True,
|
|
|
|
"randomize_upgrade_requirements": True,
|
|
|
|
"randomize_level_logic": f"{OPTIONS.logic_vanilla}_shuffled",
|
|
|
|
"randomize_upgrade_logic": OPTIONS.logic_linear,
|
|
|
|
"complexity_growth_gradient": "1e-003",
|
|
|
|
"early_balancer_tunnel_and_trash": OPTIONS.buildings_3,
|
|
|
|
"lock_belt_and_extractor": False,
|
|
|
|
"include_achievements": True,
|
|
|
|
"exclude_softlock_achievements": True,
|
|
|
|
"exclude_long_playtime_achievements": True,
|
|
|
|
"shapesanity_amount": "random",
|
|
|
|
"traps_percentage": 100,
|
|
|
|
"include_whacky_upgrades": True,
|
|
|
|
"split_inventory_draining_trap": True
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TestAllRelevantOptions4(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.efficiency_iii,
|
|
|
|
"randomize_level_requirements": True,
|
|
|
|
"randomize_upgrade_requirements": True,
|
|
|
|
"randomize_level_logic": f"{OPTIONS.logic_stretched}_shuffled",
|
|
|
|
"randomize_upgrade_logic": OPTIONS.logic_category,
|
|
|
|
"early_balancer_tunnel_and_trash": OPTIONS.sphere_1,
|
|
|
|
"lock_belt_and_extractor": False,
|
|
|
|
"include_achievements": True,
|
|
|
|
"exclude_softlock_achievements": True,
|
|
|
|
"exclude_long_playtime_achievements": True,
|
|
|
|
"shapesanity_amount": "random",
|
|
|
|
"traps_percentage": "random",
|
|
|
|
"include_whacky_upgrades": True,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TestAllRelevantOptions5(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.mam,
|
|
|
|
"goal_amount": "random-range-27-500",
|
|
|
|
"randomize_level_requirements": True,
|
|
|
|
"randomize_upgrade_requirements": True,
|
|
|
|
"randomize_level_logic": f"{OPTIONS.logic_quick}_shuffled",
|
|
|
|
"randomize_upgrade_logic": OPTIONS.logic_category_random,
|
|
|
|
"lock_belt_and_extractor": False,
|
|
|
|
"include_achievements": True,
|
|
|
|
"exclude_softlock_achievements": True,
|
|
|
|
"exclude_long_playtime_achievements": True,
|
|
|
|
"shapesanity_amount": "random",
|
|
|
|
"traps_percentage": 100,
|
|
|
|
"split_inventory_draining_trap": False
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TestAllRelevantOptions6(ShapezTestBase):
|
|
|
|
options = {
|
|
|
|
"goal": GOALS.mam,
|
|
|
|
"goal_amount": "random-range-27-500",
|
|
|
|
"randomize_level_requirements": True,
|
|
|
|
"randomize_upgrade_requirements": True,
|
|
|
|
"randomize_level_logic": OPTIONS.logic_hardcore,
|
|
|
|
"randomize_upgrade_logic": OPTIONS.logic_hardcore,
|
|
|
|
"lock_belt_and_extractor": False,
|
|
|
|
"include_achievements": False,
|
|
|
|
"shapesanity_amount": "random",
|
|
|
|
"traps_percentage": "random"
|
|
|
|
}
|