| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | import typing | 
					
						
							|  |  |  | import unittest | 
					
						
							|  |  |  | from argparse import Namespace | 
					
						
							|  |  |  | from test.general import gen_steps | 
					
						
							|  |  |  | from BaseClasses import MultiWorld, Item | 
					
						
							|  |  |  | from worlds import AutoWorld | 
					
						
							|  |  |  | from worlds.AutoWorld import call_all | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  | class WorldTestBase(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |     options: typing.Dict[str, typing.Any] = {} | 
					
						
							| 
									
										
										
										
											2022-11-01 06:45:17 -07:00
										 |  |  |     multiworld: MultiWorld | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     game: typing.ClassVar[str]  # define game name in subclass, example "Secret of Evermore" | 
					
						
							|  |  |  |     auto_construct: typing.ClassVar[bool] = True | 
					
						
							|  |  |  |     """ automatically set up a world for each test in this class """ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self) -> None: | 
					
						
							|  |  |  |         if self.auto_construct: | 
					
						
							|  |  |  |             self.world_setup() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-23 13:23:30 -07:00
										 |  |  |     def world_setup(self, seed: typing.Optional[int] = None) -> None: | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |         if not hasattr(self, "game"): | 
					
						
							|  |  |  |             raise NotImplementedError("didn't define game name") | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld = MultiWorld(1) | 
					
						
							|  |  |  |         self.multiworld.game[1] = self.game | 
					
						
							|  |  |  |         self.multiworld.player_name = {1: "Tester"} | 
					
						
							|  |  |  |         self.multiworld.set_seed(seed) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         args = Namespace() | 
					
						
							|  |  |  |         for name, option in AutoWorld.AutoWorldRegister.world_types[self.game].option_definitions.items(): | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |             setattr(args, name, { | 
					
						
							|  |  |  |                 1: option.from_any(self.options.get(name, getattr(option, "default"))) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld.set_options(args) | 
					
						
							|  |  |  |         self.multiworld.set_default_common_options() | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         for step in gen_steps: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |             call_all(self.multiworld, step) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def collect_all_but(self, item_names: typing.Union[str, typing.Iterable[str]]) -> None: | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         if isinstance(item_names, str): | 
					
						
							|  |  |  |             item_names = (item_names,) | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         for item in self.multiworld.get_items(): | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |             if item.name not in item_names: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |                 self.multiworld.state.collect(item) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def get_item_by_name(self, item_name: str) -> Item: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         for item in self.multiworld.get_items(): | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |             if item.name == item_name: | 
					
						
							|  |  |  |                 return item | 
					
						
							|  |  |  |         raise ValueError("No such item") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def get_items_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]) -> typing.List[Item]: | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         if isinstance(item_names, str): | 
					
						
							|  |  |  |             item_names = (item_names,) | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         return [item for item in self.multiworld.itempool if item.name in item_names] | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def collect_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]) -> typing.List[Item]: | 
					
						
							|  |  |  |         """ collect all of the items in the item pool that have the given names """ | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         items = self.get_items_by_name(item_names) | 
					
						
							|  |  |  |         self.collect(items) | 
					
						
							|  |  |  |         return items | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def collect(self, items: typing.Union[Item, typing.Iterable[Item]]) -> None: | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         if isinstance(items, Item): | 
					
						
							|  |  |  |             items = (items,) | 
					
						
							|  |  |  |         for item in items: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |             self.multiworld.state.collect(item) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def remove(self, items: typing.Union[Item, typing.Iterable[Item]]) -> None: | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         if isinstance(items, Item): | 
					
						
							|  |  |  |             items = (items,) | 
					
						
							|  |  |  |         for item in items: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |             if item.location and item.location.event and item.location in self.multiworld.state.events: | 
					
						
							|  |  |  |                 self.multiworld.state.events.remove(item.location) | 
					
						
							|  |  |  |             self.multiworld.state.remove(item) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def can_reach_location(self, location: str) -> bool: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         return self.multiworld.state.can_reach(location, "Location", 1) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def count(self, item_name: str) -> int: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         return self.multiworld.state.count(item_name, 1) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 09:54:41 -07:00
										 |  |  |     def assertAccessDependency(self, | 
					
						
							|  |  |  |                                locations: typing.List[str], | 
					
						
							|  |  |  |                                possible_items: typing.Iterable[typing.Iterable[str]]) -> None: | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         all_items = [item_name for item_names in possible_items for item_name in item_names] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.collect_all_but(all_items) | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         for location in self.multiworld.get_locations(): | 
					
						
							|  |  |  |             self.assertEqual(self.multiworld.state.can_reach(location), location.name not in locations) | 
					
						
							| 
									
										
										
										
											2022-10-14 19:35:53 +02:00
										 |  |  |         for item_names in possible_items: | 
					
						
							|  |  |  |             items = self.collect_by_name(item_names) | 
					
						
							|  |  |  |             for location in locations: | 
					
						
							|  |  |  |                 self.assertTrue(self.can_reach_location(location)) | 
					
						
							|  |  |  |             self.remove(items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assertBeatable(self, beatable: bool): | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.assertEqual(self.multiworld.can_beat_game(self.multiworld.state), beatable) |