78 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			78 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import unittest | ||
|  | from typing import List, Tuple | ||
|  | from unittest import TestCase | ||
|  | 
 | ||
|  | from BaseClasses import CollectionState, Location, MultiWorld | ||
|  | from Fill import distribute_items_restrictive | ||
|  | from Options import Accessibility | ||
|  | from worlds.AutoWorld import AutoWorldRegister, call_all, call_single | ||
|  | from ..general import gen_steps, setup_multiworld | ||
|  | 
 | ||
|  | 
 | ||
|  | class MultiworldTestBase(TestCase): | ||
|  |     multiworld: MultiWorld | ||
|  | 
 | ||
|  |     # similar to the implementation in WorldTestBase.test_fill | ||
|  |     # but for multiple players and doesn't allow minimal accessibility | ||
|  |     def fulfills_accessibility(self) -> bool: | ||
|  |         """
 | ||
|  |         Checks that the multiworld satisfies locations accessibility requirements, failing if all locations are cleared | ||
|  |         but not beatable, or some locations are unreachable. | ||
|  |         """
 | ||
|  |         locations = [loc for loc in self.multiworld.get_locations()] | ||
|  |         state = CollectionState(self.multiworld) | ||
|  |         while locations: | ||
|  |             sphere: List[Location] = [] | ||
|  |             for n in range(len(locations) - 1, -1, -1): | ||
|  |                 if locations[n].can_reach(state): | ||
|  |                     sphere.append(locations.pop(n)) | ||
|  |             self.assertTrue(sphere, f"Unreachable locations: {locations}") | ||
|  |             if not sphere: | ||
|  |                 return False | ||
|  |             for location in sphere: | ||
|  |                 if location.item: | ||
|  |                     state.collect(location.item, True, location) | ||
|  |         return self.multiworld.has_beaten_game(state, 1) | ||
|  | 
 | ||
|  |     def assertSteps(self, steps: Tuple[str, ...]) -> None: | ||
|  |         """Calls each step individually, continuing if a step for a specific world step fails.""" | ||
|  |         world_types = {world.__class__ for world in self.multiworld.worlds.values()} | ||
|  |         for step in steps: | ||
|  |             for player, world in self.multiworld.worlds.items(): | ||
|  |                 with self.subTest(game=world.game, step=step): | ||
|  |                     call_single(self.multiworld, step, player) | ||
|  |             for world_type in sorted(world_types, key=lambda world: world.__name__): | ||
|  |                 with self.subTest(game=world_type.game, step=f"stage_{step}"): | ||
|  |                     stage_callable = getattr(world_type, f"stage_{step}", None) | ||
|  |                     if stage_callable: | ||
|  |                         stage_callable(self.multiworld) | ||
|  | 
 | ||
|  | 
 | ||
|  | @unittest.skip("too slow for main") | ||
|  | class TestAllGamesMultiworld(MultiworldTestBase): | ||
|  |     def test_fills(self) -> None: | ||
|  |         """Tests that a multiworld with one of every registered game world can generate.""" | ||
|  |         all_worlds = list(AutoWorldRegister.world_types.values()) | ||
|  |         self.multiworld = setup_multiworld(all_worlds, ()) | ||
|  |         for world in self.multiworld.worlds.values(): | ||
|  |             world.options.accessibility.value = Accessibility.option_locations | ||
|  |         self.assertSteps(gen_steps) | ||
|  |         with self.subTest("filling multiworld", seed=self.multiworld.seed): | ||
|  |             distribute_items_restrictive(self.multiworld) | ||
|  |             call_all(self.multiworld, "post_fill") | ||
|  |             self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game") | ||
|  | 
 | ||
|  | 
 | ||
|  | class TestTwoPlayerMulti(MultiworldTestBase): | ||
|  |     def test_two_player_single_game_fills(self) -> None: | ||
|  |         """Tests that a multiworld of two players for each registered game world can generate.""" | ||
|  |         for world in AutoWorldRegister.world_types.values(): | ||
|  |             self.multiworld = setup_multiworld([world, world], ()) | ||
|  |             for world in self.multiworld.worlds.values(): | ||
|  |                 world.options.accessibility.value = Accessibility.option_locations | ||
|  |             self.assertSteps(gen_steps) | ||
|  |         with self.subTest("filling multiworld", seed=self.multiworld.seed): | ||
|  |             distribute_items_restrictive(self.multiworld) | ||
|  |             call_all(self.multiworld, "post_fill") | ||
|  |             self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game") |